C++ vector push_back

前端 未结 7 902
旧时难觅i
旧时难觅i 2020-12-23 22:03

What is the proper way of pushing a new object element onto a std::vector? I want the data to be allocated in the vector. Will this copy the object newrad

相关标签:
7条回答
  • 2020-12-23 22:17

    By default, std::vector manages the memory itself using the copy constructor of the underlying class. So, it acts a bit as if the vector element was a local variable (when the vector goes out of scope, the element gets destructed).

    When you don't want this behavior, you can use a vector of pointer or boost::ptr_vector instead.

    0 讨论(0)
  • 2020-12-23 22:23

    Try this:

    #include<iostream.h>
    #include<vector.h>
    
    class base
    {
    int i;
    public:
    
        base(int z=0){i=z;cout<<"okk constructor "<<i<<" called\n";}
        base(const base& b1){i=b1.i;cout<<"copy constructor "<<i<<" called\n";}
        void display(){cout<<" val is "<<i<<" \n";}
        ~base(){cout<<"destructor of "<<i<<" base called\n";}
    };
    
    
        int main()
        {
            cout<<"before anything\n";
            vector<base> basev;
            base baseobj1(1);
            base baseobj2(2);
            base baseobj3(3);
            base baseobj4(4);
            base baseobj5(5);
            base baseobj6(6);
            base baseobj7(7);
            base baseobj8(8);
            base baseobj9(9);
            base baseobj10(10);
    
    
            basev.push_back(baseobj1);
            cout<<"second push back\n";
            basev.push_back(baseobj2);
            cout<<"third push back\n";
            basev.push_back(baseobj3);
            cout<<"fourth push back\n";
            basev.push_back(baseobj4);
            cout<<"fifth push back\n";
            basev.push_back(baseobj5);
            cout<<"sixth push back\n";
            basev.push_back(baseobj6);
            cout<<"seventh push back\n";
            basev.push_back(baseobj7);
            cout<<"eighth push back\n";
            basev.push_back(baseobj8);
            cout<<"ninth push back\n";
            basev.push_back(baseobj9);
            cout<<"10th push back\n";
            basev.push_back(baseobj10);
            cout<<"after all push back\n";
    
    
            cout<<"before clear\n";
            basev.clear();
            cout<<"after clear\n";
    
    
    }
    

    output:

    before anything
    okk constructor 1 called
    okk constructor 2 called
    okk constructor 3 called
    okk constructor 4 called
    okk constructor 5 called
    okk constructor 6 called
    okk constructor 7 called
    okk constructor 8 called
    okk constructor 9 called
    okk constructor 10 called
    copy constructor 1 called
    second push back
    copy constructor 1 called
    copy constructor 2 called
    destructor of 1 base called
    third push back
    copy constructor 1 called
    copy constructor 2 called
    copy constructor 3 called
    destructor of 1 base called
    destructor of 2 base called
    fourth push back
    copy constructor 4 called
    fifth push back
    copy constructor 1 called
    copy constructor 2 called
    copy constructor 3 called
    copy constructor 4 called
    copy constructor 5 called
    destructor of 1 base called
    destructor of 2 base called
    destructor of 3 base called
    destructor of 4 base called
    sixth push back
    copy constructor 6 called
    seventh push back
    copy constructor 7 called
    eighth push back
    copy constructor 8 called
    ninth push back
    copy constructor 1 called
    copy constructor 2 called
    copy constructor 3 called
    copy constructor 4 called
    copy constructor 5 called
    copy constructor 6 called
    copy constructor 7 called
    copy constructor 8 called
    copy constructor 9 called
    destructor of 1 base called
    destructor of 2 base called
    destructor of 3 base called
    destructor of 4 base called
    destructor of 5 base called
    destructor of 6 base called
    destructor of 7 base called
    destructor of 8 base called
    10th push back
    copy constructor 10 called
    after all push back
    before clear
    destructor of 1 base called
    destructor of 2 base called
    destructor of 3 base called
    destructor of 4 base called
    destructor of 5 base called
    destructor of 6 base called
    destructor of 7 base called
    destructor of 8 base called
    destructor of 9 base called
    destructor of 10 base called
    after clear
    destructor of 10 base called
    destructor of 9 base called
    destructor of 8 base called
    destructor of 7 base called
    destructor of 6 base called
    destructor of 5 base called
    destructor of 4 base called
    destructor of 3 base called
    destructor of 2 base called
    destructor of 1 base called
    
    0 讨论(0)
  • 2020-12-23 22:29

    Yes pushing newRadio will push a copy of the Radio object into the vector. You also don't need to free the vector because it is local only so it will be destroyed once you are out of its scope. If for instance you wrote

    vector<Radio> *m_radios = new vector<Radio>();
    

    Then you would have to free that memory by calling the vector destructor manually.

    0 讨论(0)
  • 2020-12-23 22:35

    std::vector manages its own memory. That means that, when the destructor of a vector is invoked the memory held by the vector is released. std::vector also invokes an object's destructor when it is removed (through erase, pop_back, clear or the vector's destructor).

    When you do this:

    Radio newradio(radioNum);
    m_radios.push_back(newradio);
    

    You add a copy of newradio (created using Radio's copy constructor) to the vector. newradio will be destroyed when it goes out of scope, and the copy will be destroyed when it is removed from the vector (as for any object).

    That's an important point: std::vector only stores copies of an object, which means the object must have a meaningful copy constructor (and an assignment operator, but that's another issue). If you have a vector of pointers, then the pointer itself will be copied, and not what it points to. Note that this behavior is the same for every standard container (like std::list or std::set).

    As a rule of thumb, if you're not using pointers, then you don't have to worry about releasing the memory yourself.

    In C++11, most standard containers (including vector) have an emplace_back method that constructs an object in place at the end of the container. It takes a bunch of parameters and calls the constructor that best matches those parameters (or fails if no such constructor exist), using said constructor to create the object, without any copy, at the end of the container. So, the above code could be rewritten as:

    m_radios.emplace_back(radioNum); // construct a Radio in place, 
                                     // passing radioNum as the constructor argument
    

    Also in C++11, containers are usually move aware, so they no longer require objects to be copiable: if they are movable, then the container will move its contents as required (such as during reallocations, for instance). Copiable types are still required if you want to copy the vector.

    0 讨论(0)
  • 2020-12-23 22:36

    Yup, radioNum will be copied into m_radios. As long as you're not deallocating pointers when newradio.~Radio(); occurs (out of scope), it's OK. If m_radios, or a subclass uses pointers, you'll need to make the switch to smart pointers (shared_ptr).

    When m_radios goes out of scope, the destructor is automatically called, and all the stuff std::vector holds is freed.

    0 讨论(0)
  • 2020-12-23 22:37

    push_back() will store a copy of its argument within the vector. As long as Radio implements proper value semantics, there will be no problems with it.

    0 讨论(0)
提交回复
热议问题