Reputation: 2180
I'm trying to invoke the move constructor in the code below, where the addition of two lists occurs. Given what I read in the Stroustrup book, the move constructor should be invoked when operator+(const X& a, const X& b)
returns, however it does not per the output below. Only the move assignment is being invoked.
Does anyone know why the move constructor is not being invoked on return from function?
Thanks
#include <iostream>
#include <list>
using std::list;
using std::cout;
using std::initializer_list;
class X {
list<int> *p;
size_t sz;
public:
X() : p{ new list<int>(0) } { }
X(size_t size) : p{ new list<int>(size) }, sz {size} { }
X(initializer_list<int> li) : p{ new list<int>(li) }, sz { li.size() } { }
X(const X&);
X& operator=(const X&);
// move
X(X&&);
X& operator=(X&&);
size_t size() const { return sz; }
int &operator[](int);
int &operator[](int) const;
class size_mismatch { };
};
X::X(const X& a)
{
p = new list<int>();
for (auto pp : *(a.p))
p->push_back(pp);
sz = a.sz;
}
X& X::operator=(const X& a)
{
delete p;
p = new list<int>();
for (auto pp : *(a.p))
p->push_back(pp);
sz = a.sz;
return *this;
}
X::X(X&& a) : p{ a.p }, sz{ a.sz }
{
cout << "here0\n";
a.p = nullptr;
a.sz = 0;
}
X& X::operator=(X&& a)
{
cout << "here1\n";
p = a.p;
sz = a.sz;
a.p = nullptr;
a.sz = 0;
return *this;
}
int& X::operator[](int x)
{
for (auto &i : *p) {
if (x == 0) return i;
--x;
}
throw std::out_of_range("List container");
}
int& X::operator[](int x) const
{
for (auto &i : *p) {
if (x == 0) return i;
--x;
}
throw std::out_of_range("List container");
}
X operator+(const X& a, const X& b)
{
if (a.size()!=b.size())
throw X::size_mismatch{};
X res(a.size());
for (int i = 0; i != a.size(); ++i)
res[i] = a[i] + b[i];
return res;
}
int main(int argc, char *argv[])
{
X px = {0, 1, 2};
for (int i=0; i < px.size(); i++)
cout << px[i];
cout << '\n';
X py(px);
for (int i=0; i < py.size(); i++)
py[i]++;
for (int i=0; i < py.size(); i++)
cout << py[i];
cout << '\n';
X pz;
pz = py;
for (int i=0; i < pz.size(); i++)
cout << pz[i];
cout << '\n';
X ph;
// This should call move constructor
ph = px + py + pz;
for (int i=0; i < ph.size(); i++)
cout << ph[i];
cout << '\n';
return 0;
}
$ g++ -std=c++11 test62.cc && ./a.out
012
123
123
here1
258
Upvotes: 0
Views: 59
Reputation: 60238
In this snippet:
X ph;
// This should call move constructor
ph = px + py + pz;
ph
is already created, so there is no question of calling the move constructor.
If you change the snippet to:
X ph = px + py + pz;
you still won't call the move constructor, due to copy-elision.
You can see the move constructor being invoked if you explicitly std::move
the result in the return statement of operator+
:
X operator+(const X& a, const X& b)
{
// ...
return std::move(res);
}
Here's a demo.
Upvotes: 2