2

I am wondering why the std::vector does not use move constructor when it grows dynamically. Or is it some problem with my code? Please see below my test code:

#include<vector>
#include<iostream>
#include<cstring>

using namespace std;
class test{
public:
    char *ptr; 
public:
    test()
        :ptr{new char[10]}{
            strcpy(ptr,"hello");
            cout<<"constructor called"<<endl;
        }
    test(const test& t){
        ptr = new char[10];
        strcpy(ptr,t.ptr);
        cout<<"copy constructor called"<<endl;
    }
    test(test &&t){
        this->ptr = t.ptr;
        t.ptr = nullptr;
        cout<<"move constructor called"<<endl;
    }
    ~test(){
        cout<<"destructor called"<<endl;
        delete[] ptr;
    }
};

vector<test> function()
{
    vector<test> v;
    cout<<v.size()<<" "<<v.capacity()<<endl;
    v.push_back(test{});
    cout<<v.size()<<" "<<v.capacity()<<endl;
    v.push_back(test{});
    cout<<v.size()<<" "<<v.capacity()<<endl;
    return v;
}

int main()
{ 
    vector<test> v = function();
}

the output of above code is as follows:

0 0
constructor called
move constructor called
destructor called
1 1
constructor called
move constructor called
copy constructor called
destructor called
destructor called
2 2
destructor called
destructor called

Even though the class test has a move constructor, still vector uses copy constructor when it resizes internally. Is it the expected behavior or is it because of some problem with test class itself?

thanks for your answers.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
whitetiger
  • 412
  • 1
  • 4
  • 13
  • 1
    Depending on your compiler, the move constructor for class `test` needs to be `noexcept` for `std::vector` to use it. – AndyG Dec 21 '15 at 20:43
  • It looks like it's moving the object that's already in the vector but using the copy constructor for the new element (since `push_back` takes a const reference). – Kevin Dec 21 '15 at 20:44
  • @Kevin `push_back` is overloaded to take either `const value_type&` or `value_type&&`. I think the copy is in fact the object already in the vector. – aschepler Dec 21 '15 at 20:45
  • @Kevin `push_back` has two overloads one with `const reference` and one with forwarding reference. – 101010 Dec 21 '15 at 20:45
  • 4
    It is all about `noexcept`. Move needs to be `nothrow` to allow `std::vector` to fulfill it's exception guarantees. – Johan Lundberg Dec 21 '15 at 20:46
  • 1
    Now that I've actually read the question, I think OP is actually looking for `emplace_back`. Well, a combination of that and `noexcept`. [Demo](http://coliru.stacked-crooked.com/a/e3500437f1e9f3ea) – AndyG Dec 21 '15 at 20:47
  • 2
    You violate the rule of five (missing assignment operators) –  Dec 21 '15 at 20:47
  • @101010 and aschepler I didn't realize that C++11 added that. Good to know! – Kevin Dec 21 '15 at 20:48
  • thank you @AndyG, by just making the move constructor as noexcept , the vector uses move constructor when it grows dynamically. thank you all. – whitetiger Dec 21 '15 at 20:51

0 Answers0