精华内容
下载资源
问答
  • vector 中 emplace_backpush_back的区别: 1.push_back() 向容器尾部添加元素时,首先会创建这个元素,然后再将这个元素拷贝或者移动到容器中(如果是拷贝的话,事后会自行销毁先前创建的这个元素);而emplace_...

    vector 中 emplace_back和push_back的区别:

    1.push_back() 向容器尾部添加元素时,首先会创建这个元素,然后再将这个元素拷贝或者移动到容器中(如果是拷贝的话,事后会自行销毁先前创建的这个元素);而emplace_back() 在实现时,则是直接在容器尾部创建这个元素,省去了拷贝或移动元素的过程。

    2.若vector<pair<,>>这种情况 push_back({x.y}) 要以pair的格式添加, 而emplace_back(x,y) 不需要加{}

    展开全文
  • vectorpush_back和emplace_back区别区别测试代码vector空间自动增长代码 正常情况下push_back是往vector中添加新的元素,只不过添加过程是先利用拷贝构造函数复制目标值,而 emplace_back可以 直接在目标位置上...

    vector中push_back和emplace_back区别

    正常情况下push_back是往vector中添加新的元素,只不过添加过程是先利用拷贝构造函数复制目标值,而 emplace_back可以 直接在目标位置上生成对象,这也正式emplace的原本放置的意思。
    具体在使用上,如果push的对象元素是已经生成好了的(如Nelson),emplace_back和push_back可以认为没有区别,如果原本没有要push的这个元素,则直接原地生成效率较高;

    实际在push的时候,由于vector内存需要连续,在vector size达到1, 2,4,8…时其长度需要自动增加,故四二次push时首先生成目标元素,检测到现有存储空间已满,会调用复制构造函数来重头到尾复制前面的vector元素,依次push进去vector之后再析构掉复制的元素,最后再将目标元素push进去;

    一般移动构造函数的输入为右值,操作完成后右值内容就为空了(数字除外),具体过程可由std::move(左值) 进行模仿.
    如果传入的为右值但没有定义移动构造函数,则可调用拷贝构造函数。即emplace_back和push_back均可接收左值(普通变量)和右值(无名临时对象),左值调用复制构造函数,右值调用移动构造函数,表现一致;

        President joy("joy ", "USA", 2021);
        elections.emplace_back(std::move(joy));
        elections.emplace_back(std::move(joy));
        elections.emplace_back(std::move(joy));
    //输出结果
    joy  elected president of USA in 2021.
    	  elected president of 		   in 2021.
     	  elected president of 		   in 2021.
    

    emplace_back结果
    elections.emplace_back(“Nelson Mandela”, “South Africa”, 1994)
    I am being constructed.
    elections.emplace_back(Nelson);
    I am being constructed.
    I am being copy constructed.
    moved:
    joy USA2021
    elections.emplace_back(std::move(Nelson));
    I am being constructed.
    I am being moved.
    moved:
    2021

    push_back结果
    reElections.push_back(President(“Franklin Delano Roosevelt”, “the USA”, 1936))
    I am being constructed.
    I am being moved.
    I am being destructed.
    reElections.push_back(obama);
    I am being constructed.
    I am being copy constructed.
    moved:
    Franklin USA1966
    reElections.push_back(std::move(obama));
    I am being constructed.
    I am being moved.
    moved:
    1966

    区别测试代码

    这里是参考博客 ().

    // An highlighted block
    #include <vector>  
    #include <string>  
    #include <iostream>  
    
    struct President  
    {  
        std::string name;  
        std::string country;  
        int year;  
    
        President(std::string p_name, std::string p_country, int p_year)	//构造函数
        :name(p_name), country(p_country), year(p_year)  
        {  std::cout << "I am being constructed.\n"; }
        
        President(const President& other)	//拷贝构造函数
        :name(other.name), country(other.country), year(other.year)
        { std::cout << "I am being copy constructed.\n";}
        
        President(President&& other)		//移动构造函数
        :name(std::move(other.name)), country(std::move(other.country)), year(other.year)  
        { std::cout << "I am being moved.\n"; }  
        
        President& operator=(const President& other);  
        
        ~President()
        { std::cout << "I am being destructed.\n";} 
    };  
    
    int main()  
    {  
        std::vector<President> elections;  
        std::cout << "emplace_back:\n";  
        elections.emplace_back("Nelson ", "frica", 1994); //没有类的移动
        elections.emplace_back("Nelson ", "Africa", 1995); 
        elections.emplace_back("Nelson ", "Africa", 1996); 
            President joy("joy ", "USA", 2021);
        elections.emplace_back(std::move(joy));
    
        
        std::vector<President> reElections;  
        std::cout << "\npush_back:\n";  
        reElections.push_back(President("Franklin ", "USA", 1936));  
        reElections.push_back(President("Franklin ", "USA", 1937));
        reElections.push_back(President("Franklin ", "USA", 1938));
        
        President obama("obama ", "USA", 1966);
        reElections.push_back(obama);
        std::cout << "moved:\n" << obama.name
             << obama.country << obama.year <<std::endl;
        std::cout << "\nContents:\n";  
        for (President const& president: elections) {  
           std::cout << president.name << " elected president of "  
                << president.country << " in " << president.year << ".\n";  
        }  
        for (President const& president: reElections) {  
            std::cout << president.name << " re-elected president of "  
                << president.country << " in " << president.year << ".\n";  
        }
    }
    

    结果输出
    emplace_back:
    I am being constructed.
    I am being constructed.
    I am being copy constructed.
    I am being destructed.
    I am being constructed.
    I am being copy constructed.
    I am being copy constructed.
    I am being destructed.
    I am being destructed.

    push_back:
    I am being constructed.
    I am being moved.
    I am being destructed.
    I am being constructed.
    I am being moved.
    I am being copy constructed.
    I am being destructed.
    I am being destructed.
    I am being constructed.
    I am being moved.
    I am being copy constructed.
    I am being copy constructed.
    I am being destructed.
    I am being destructed.
    I am being destructed.

    Contents:
    Nelson elected president of frica in 1994.
    Nelson elected president of Africa in 1995.
    Nelson elected president of Africa in 1996.
    Franklin re-elected president of USA in 1936.
    Franklin re-elected president of USA in 1937.
    Franklin re-elected president of USA in 1938.
    I am being destructed.
    I am being destructed.
    I am being destructed.
    I am being destructed.
    I am being destructed.
    I am being destructed.

    vector空间自动增长测试代码

    #include <iostream>
    #include <vector>
    
    using std::cout; 
    using std::endl;
    
    struct X{
        X(int a) {x=a;cout << "调用构造函数:X()" << a << endl;}
        X(const X& Xa) {x=Xa.x; cout << "调用拷贝构造函数:X(const X&)" << x << endl;}
        ~X(){cout << "调用析构函数:~X()" << x << endl;}
    	int x;
    };
    
    int main(int argc, char **argv)
    {
        cout << "定义局部变量:" << endl;
        X x(1);
    	X y(2);
    
        std::vector<X> vec;
        cout << "\n存放在容器:" << endl;
        vec.push_back(y);
    	vec.push_back(x);
    	vec.push_back(y);
        cout << endl;
    
        cout << "程序结束!!!" << endl;
        return 0;
    }
    

    输出结果

    定义局部变量:
    调用构造函数:X()1
    调用构造函数:X()2
    存放在容器:
    调用拷贝构造函数:X(const X&)2
    调用拷贝构造函数:X(const X&)1
    调用拷贝构造函数:X(const X&)2
    调用析构函数:~X()2
    调用拷贝构造函数:X(const X&)2
    调用拷贝构造函数:X(const X&)2
    调用拷贝构造函数:X(const X&)1
    调用析构函数:~X()2
    调用析构函数:~X()1
    程序结束!!!
    调用析构函数:~X()2
    调用析构函数:~X()1
    调用析构函数:~X()2
    调用析构函数:~X()2
    调用析构函数:~X()1

    展开全文
  • 首先贴函数的申明和定义部分源码: template<...class vector : protected _Vector_base<_Tp, _Alloc> { typedef _Tp value_type; void push_back(const value_type& __x) { if (this-&

    首先贴函数的声明和定义部分源码:

    template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
    class vector : protected _Vector_base<_Tp, _Alloc>
    {
          typedef _Tp value_type;
    
          void  push_back(const value_type& __x)
          {
    	    if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
    	    {
    	        _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
    				     __x);
    	        ++this->_M_impl._M_finish;
    	    }
    	    else
    	      _M_realloc_insert(end(), __x);
          }
    
    #if __cplusplus >= 201103L
          void
          push_back(value_type&
                    & __x)
          { emplace_back(std::move(__x)); }
    
          template<typename... _Args>
    #if __cplusplus > 201402L
    	reference
    #else
    	void
    #endif
    	emplace_back(_Args&&... __args);
    #endif
    
         // ... 省略
    };

     

    说说区别:

    使用emplace_back比push_back 更加高效。

    怎么解释?上一段验证代码:

    class Student{
    public:
    
        Student(int age,string name):age_(age),name_(name){
            std::cout << "[" << __FUNCTION__ << ":" << __LINE__  << "    Student(int age,string name)]" << std::endl;
            std::cout << *this << std::endl;
        }
    
        Student(const Student& that){
            std::cout << "[" << __FUNCTION__ << ":" << __LINE__  << "  Student(const Student& that)]" << std::endl;
            std::cout << that << std::endl;
        }
    
        ~Student(){
            std::cout << "[" << __FUNCTION__ << ":" << __LINE__  << "  ~Student()]" << std::endl;
            std::cout << *this << std::endl;
        }
    
        friend ostream& operator <<(ostream& os,const Student& that){
            os << "[" <<__FUNCTION__ << ":" << __LINE__  << "] : " << that.name_ << "    " << that.age_ << endl;
            return os;
        }
    
    private:
        int age_;
        string name_;
    };
    
    int main(int argc,char* argv[])
    {
        vector<Student> v;
    
        {
            v.push_back(Student(12,string("zhangsan")));
        }
    
        {
            //v.emplace_back(12,string("lisi"));
        }
        return 0;
    }
    

    输出结果:

    分别执行两种插入方式:
    
    
    
    [Student:22    Student(int age,string name)]
    [operator<<:37] : zhangsan    12
    
    [Student:27  Student(const Student& that)]
    [operator<<:37] : zhangsan    12
    
    [~Student:32  ~Student()]
    [operator<<:37] : zhangsan    12
    
    [~Student:32  ~Student()]
    [operator<<:37] :     7019200
    
    -----------------------------------------------------------
    
    [Student:22    Student(int age,string name)]
    [operator<<:37] : lisi    12
    
    [~Student:32  ~Student()]
    [operator<<:37] : lisi    12
    

    很明显可以看到,使用emplace_back 比使用push_back要少执行一次拷贝构造和析构

    展开全文
  • STL vector push_back详解

    2021-03-15 18:43:56
    vectorpush_back操作是将一个元素插入vector的末尾。源码如下:template void YVector::push_back(const T&x){if (finish !=end_of_storage){construct(finish, x);++finish;}else{insert_aux(finish, x);}}...

    vector的push_back操作是将一个元素插入vector的末尾。

    源码如下:

    template

    void YVector::push_back(const T&x)

    {if (finish !=end_of_storage)

    {

    construct(finish, x);++finish;

    }else{

    insert_aux(finish, x);

    }

    }

    函数insert_aux

    template

    void YVector::insert_aux(iterator position, const T&x)

    {if (finish !=end_of_storage)

    {

    construct(finish,*(finish - 1));++finish;

    T copy_x=x;

    copy_backward(position, finish- 2, finish - 1);*position =copy_x;

    }else{const size_type old_size =size();const size_type new_size = old_size == 0 ? 1 : 2 *old_size;

    iterator new_start=data_allocator::allocate(new_size);

    iterator new_finish=new_start;try{

    new_finish=uninitialized_copy(start, position, new_start);

    construct(new_finish, x);++new_finish;

    new_finish=uninitialized_copy(position, finish, new_finish);

    }catch(...)

    {

    destroy(new_start, new_finish);

    data_allocator::deallocate(new_start, new_size);throw;

    }

    destroy(begin(), end());

    deallocate();

    start=new_start;

    finish=new_finish;

    end_of_storage= new_start +new_size;

    }

    }

    需要理解以上源码并不容易。看我一一道来。

    1.start,finish,end_of_storage

    首先必须了解vector的数据结构。如图:

    d84488485eaeeab62ab43020cc2e5d79.png

    vector是一段连续的内存空间。start,finish,end_of_storage三个指针描述了空间状态,这三个是普通的指针。start到finish是已经使用的内存,里面有元素。finish到end_of_storage是未使用的内存,里面没有元素。

    由此三个指针可以得出一些简单的操作。

    iterator begin() { return start; } //起始位置

    iterator end() { return finish; } //结束位置

    size_type size() const { return size_type(end() - begin()); } //已可用大小

    size_type capacity() const { return size_type(end_of_storage - begin()); } //申请的内存大小

    bool empty() { return begin() == end(); } //是否为空

    reference operator[](size_type n) { return *(begin() + n); } //[]操作

    reference front() { return *begin(); } //首元素

    reference back() { return *(end() - 1); } //尾元素

    其中一些定义

    typedef T value_type;

    typedef value_type*pointer;

    typedef value_type*iterator;

    typedef value_type&reference;

    typedef size_t size_type;

    2.construct,destroy

    这个两个是全局的构造和析构函数。其中construct是调用placement new。

    有关于placement new,参考 http://www.cnblogs.com/luxiaoxun/archive/2012/08/10/2631812.html

    templateinlinevoid construct(T1* p, const T2&value)

    {new(p)T1(value);

    }

    placement new可以简单理解成在已经分配好的空间上构造。

    在puch_back这里的情境中,如果内存的备用区还有空间,则用x在finish指向的空间上构造,同时移动finish指针。这里原本finish指向的空间是已经申请了的,所以使用placement new。

    if (finish !=end_of_storage)

    {

    construct(finish, x);++finish;

    }

    destroy有两个版本。destroy实现较复杂,参看《STL源码剖析》第二章。只需知道destroy会在指定范围进行析构。

    template inlinevoid destroy(T*pointer)

    {

    pointer->~T();

    }

    templateinlinevoiddestroy(ForwardIterator first, ForwardIterator last)

    {

    //实现略

    }

    3.allocate,deallocate

    注意到定义类时出现了Alloc,这其实是配置器。vector默认使用alloc配置器。

    template

    在基本的alloc上封装一层simple_alloc。如下:

    template

    classsimple_alloc {static T* allocate(size_t n)

    { return n == 0 ? 0 : (T*)Alloc::allocate(n * sizeof(T)); }static T* allocate()

    { return (T*)Alloc::allocate(sizeof(T)); }static void deallocate(T *p, size_t n)

    { if (n == 0) Alloc::deallocate(p, n * sizeof(T)); }static void deallocate(T *p)

    { Alloc::deallocate(p, sizeof(T)); }

    };

    实际上内部实现就是调用malloc和free,但是会有复杂的分级配置处理。在此不再讨论。参看《STL源码剖析》第二章。

    可以就简单的把allocate,deallocate理解成malloc,free来辅助记忆,但务必记得没那么简单。

    4.uninitialized_copy,copy_backward

    uninitialized_copy处理如下图:

    69408527c3d9ccc930b59ffa4b02f132.png

    看起来好复杂……来看一下原型:

    template inline ForwardIterator

    uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator result)

    {return__uninitialized_copy(first, last, result, value_type(result));

    }

    如果[result,result + (last - first))范围内的迭代器都指向未初始化区域,则uninitialized_copy()会使用copy construct给输入来源[first,last)范围内的每一个对象产生一个拷贝放进输出范围。

    更深的实现也贴出来:

    template inline ForwardIterator

    __uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator result, T*)

    {

    typedef typename __type_traist::is_POD_type is_POD_type is_POD;return__uninitialized_copy_aux(first, last, result, is_POD());

    }

    templateinline ForwardIterator

    __uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator result, __true_type)

    {returncopy(first, last, result);

    }

    templateinline ForwardIterator

    __uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator result, __false_type)

    {

    ForwardIterator cur=result;for (; last != first; first++, cur++)

    {

    construct(&*cur, *first);

    }returncur;

    }

    这里面的逻辑是,首先把result的value_type得出,判断是否是POD类型……

    如果是POD类型,则调用copy函数,如果不是POD类型,则一个一个调用construct()

    所谓POD类型,指的是拥有无意义的构造、析构、拷贝、赋值函数的类型…能不能理解成比较简单的类。

    像是如果类成员里有一个其他类的指针,这种复杂的类,需要有特殊的构造函数,就没有默认的那个构造函数。因此是non-POD类型。

    接下来回到push_back。insert_aux里面判断还有备用空间的地方,有一个copy_backword函数。来看一下实现:

    templateBidirectionalIterator2 copy_backward ( BidirectionalIterator1 first,

    BidirectionalIterator1 last,

    BidirectionalIterator2 result )

    {while (last!=first) *(--result) = *(--last);returnresult;

    }

    作用是将一个范围中的元素按逆序拷贝到新的位置处。insert_aux截取如下:

    if (finish !=end_of_storage)

    {

    construct(finish,*(finish - 1));++finish;

    T copy_x=x;

    copy_backward(position, finish- 2, finish - 1);*position =copy_x;

    }

    这里面有两个问题。第一为什么要有一份拷贝T copy_x = x;问题的答案参考知乎 https://www.zhihu.com/question/56911557/answer/150928396

    第二个 copy_backward(position,finish - 2,finish - 1) 在插入位置是末尾的时候不会死循环吗?黑人问号?

    position其实是finish - 1,也就是说传入参数后first比last还后面,那岂不是死循环?

    引用:

    1.《STL源码剖析》

    2.http://www.cnblogs.com/luxiaoxun/archive/2012/08/10/2631812.html

    展开全文
  • push_back和emplace_back比较以及vector扩容push_back和emplace_back的比较使用测试类测试过程将实体类对象传入将右值数字传入将实体类对象move()转右值之后传入vector扩容过程 关于这部分内容,也是C++中的...
  • vector 中 emplace_backpush_back的区别: 1.push_back() 向容器尾部添加元素时,首先会创建这个元素,然后再将这个元素拷贝或者移动到容器中(如果是拷贝的话,事后会自行销毁先前创建的这个元素);而emplace_...
  • 在C11中,有两种方法可以把元素放入容器中:emplace_backpush_backpush_back是C11之前就有的,而emplace_back是C11中新加的。 既然它们的作用都是一样的,那么为什么C11中又加入了一个emplace_back? 既生瑜,何...
  • vector::push_back

    2021-05-24 09:06:49
    vector::push_back描述 (Description)C ++函数std::vector::push_back()在向量的末尾插入新元素,并将向量的大小增加1。声明 (Declaration)以下是std :: vector :: push_back()函数形式std :: vector标头的声明。C++...
  • vec.push_back(vector<int>()); vec.back().push_back(); 今天在刷leetcode题的时候见到如上三句代码,很有意思。 第一句创建了一个实体为vertor<int>的容器,可以理解为一个二维数组; 第二句话相当...
  • 我测下的结果,反而是push_back耗时更小些。这个明显和大家的结论不一致。 #include <vector> #include <iostream> #include <sys/time.h> using namespace std; int64_t GetSysTimeMicros() ...
  • } 2、不同的情况 同样以vector test为例,根据vector中存放的不同类型,push_back()可以识别元素类型;emplace_back()需要显式标注出是何种类型,具体见下述代码 int main() { vector<int> test; test.push_back...
  • 具有push_back()和emplace_back()函数功能的容器:deque、list、vector 相同点:都是往容器末尾添加元素 区别:底层实现机制不同 push_back()向容器尾部添加元素时,首先会创建这个元素,然后再将这个元素拷贝或...
  • 在 STL 的容器中,除了给 vector 等序列容器定义了push_back方法之外,还定义了emplace_back方法; 除了给 map 等关联容器定义了insert方法外,还定义了emplace方法。 那么,emplace_back/emplace 和 push_back/...
  • push_back() 创建一个新元素,然后拷贝构造到容器的末尾。 emplace_back() 直接在容器尾部构造对象,直接调用构造函数进行构造,省去对象拷贝构造的过程。 有案例的链接
  • 1 出现的问题 vector<int> smallestK(vector<int>& arr, int k) ... res.push_back(arr[i]); return res; } 其中arr={3,4,5},k=2, 返回的结果是{0, 0, 3, 4}. 即出现了两个多余的
  • emplace_back() 和 push_back() 的区别,就在于底层实现的机制不同。 push_back() 向容器尾部添加元素时,首先会创建这个元素,然后再将这个元素拷贝或者移动到容器中(如果是拷贝的话,事后会自行销毁先前创建的这...
  • 一、什么是vector? 向量(Vector)是一个封装了动态大小数组的顺序容器(Sequence Container)。跟任意其它类型容器一样,它能够存放各种类型的对象。可以简单的认为,向量是一个能够存放任意类型的动态数组。 二、...
  • push_back() 该成员函数的功能是在 vector 容器尾部添加一个元素。 eg: #include <iostream> #include <vector> using namespace std; int main() { vector<int> values; values.push_back(1);...
  • 去试一下呗,网上千篇一律,什么直接再序列尾部直接构造,什么emplace比vector省去一步拷贝。 真有提升好多性能呢,其实好好想想怎么给数据库调优,IO调优,架构调优也挺实在呢。 我插了一千万个类对象,两个时间都...
  • 学习 emplace_back() 和 push_back 的区别 emplace_back效率高 在引入右值引用,转移构造函数,转移复制运算符之前,通常使用push_back()向容器中加入一个右值元素(临时对象)的时候,首先会调用构造函数构造这个...
  • 此外,本文还将简述push对应的stack与queue系列,常见方法的介绍,以及与push_back相对应的vector系列常见方法介绍。详见下文。list 也是使用 push_back .【正文】push_back 方法介绍vector::v...
  • 如果传递的对象,push_back就是对象的副本,push_back后,在改变对象的值,将对vector 的副本对象不起作用。 如果传递的是指针,push_back就是指针的副本,push_back后,通过指针改变对象的值,会影响到vector中的...
  • 因此产生一个疑问,就是push_back(),这个函数是往Vector中添加元素,当容量不够时,会自动添加容量。但push_back()是在末尾添加的,所以这个函数导致的容量增加会改变首地址吗? 因此,通过下面的代码来进行验证。 ...
  • 在STL中,向vector容器添加元素的函数有2个:push_back()、emplace_back() 1.push_back() 在vector容器尾部添加一个元素,用法为: arr.push_back(val); 2.emplace_back() C++11新增,功能与push_back相同,...
  • size capacity size :vector中元素个数 ...而不断的push_back,会导致不断的拷贝操作,影响效率。 resize(n), 改变size 的大小(改变vector中元素的数目),并给新的元素赋值 reserve(n),只是改变c.
  • vectorpush_back无法赋值?-CSDN社区 问题来源: 浙大数据结构2021秋 02-线性结构3 Reversing Linked List (25 分) 本题同PAT1025 但1025未使用vector容器 错误原因: vector<struct Node> v(n); for ...
  • 文章目录push back调用方式传入右值传入左值emplace_back 调用 push back调用方式 传入右值 如果调用 push_back,传入的是右值 vec_bc.push_back(BaseClass("b3", 1)); 则,需要执行以下步骤 1. 调用构造函数,构造...
  • push_bach(): 首先调用构造函数构造一个临时对象,然后在容器尾部区域利用这个临时对象进行拷贝构造,最后释放临时变量。 emplace_back(): 这个元素原地构造,不需要触发拷贝构造和转移构造。 详细测试见代码: #...
  • c++ push_back与emplace_back

    2021-04-15 11:28:32
    push_back与emplace_back 本节直接讨论在向容器添加数据时,插入(push_backpush_front、insert等)和置入(emplace_back)的内存性能情况,深入了解C++的内部机制。考虑下面代码: vector<string> vs; vs.push_...
  • std::vectorpush_back与拷贝构造 移动构造的关系 #include <iostream> #include <vector> class T { public: T() = default; T(int32_t i) { m_indx = i; printf("constructor T\n"); } T...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 550,915
精华内容 220,366
关键字:

push_backvector