Reputation: 889
I want to know what's happening here:
class Test {
public:
Test() { std::cout << "Constructor" << std::endl; }
Test(const Test &) { std::cout << "Copy" << std::endl; }
Test(const Test &&) { std::cout << "Move" << std::endl; }
~Test() { std::cout << "Destructor" << std::endl; }
};
std::vector<Test> getTestVektor() {
std::vector<Test> TestVektor(1);
return TestVektor;
}
Test getTest() {
Test TestVariable;
return TestVariable;
}
int main() {
{
std::vector<Test> TestVektor = getTestVektor();
}
std::cout << std::endl;
{
Test TestVarible = getTest();
}
std::cout << std::endl;
{
std::vector<Test> TestVektor(1);
std::vector<Test> TestVektor2 = TestVektor;
}
return 0;
}
compiled with VisualStudio 2012:
Constructor
Destructor
Constructor
Move
Destructor
Destructor
Constructor
Copy
Destructor
Destructor
One could explain the first case with copy elision. But that's contrary to the second case, where the move constructor was called.
Another explanation would be, that the std::vector in the function releases its contents and passes it to the second std::vector, so there is no call of the copy constructor. But the third case shows, that that's not the case.
So, what's happening here? Or is this just mazy compiler opitimization?
Upvotes: 1
Views: 357
Reputation: 238351
One could explain the first case with copy elision.
TestVektor
was move constructed from the temporary vector that was returned from getTestVektor
. One, both or neither of the moves may have been elided.
But that's contrary to the second case, where the move constructor was called.
Copy/move elision is not mandatory. It could be used for both the return from getTest
and copy initialization of TestVarible
, but it wasn't used for one of them.
Versions of both GCC and Clang that I tested elided both.
Another explanation would be, that the std::vector in the function releases its contents and passes it to the second std::vector
That's exactly what the move constructor of std::vector
does.
But the third case does copy assignment, not a move construction.
In conclusion, what's happening here is mostly explained by the move constructor of std::vector
, but the second case also shows observable (lack of) side effects from copy/move elision.
Upvotes: 0
Reputation: 69882
FYI the output from clang, with -O2:
Constructor
Destructor
Constructor
Destructor
Constructor
Copy
Destructor
Destructor
Why visual studio would invoke a move in case 2 is a mystery to me. Did you disable optimisations?
Upvotes: 0
Reputation: 217293
The first case (at worst) moves the vector (so just transfers the internal pointer, without copy/move of Test
).
The 3rd case makes a copy of vector, you would have to do the following to move it instead of copy:
{
std::vector<Test> TestVektor(1);
std::vector<Test> TestVektor2 = std::move(TestVektor);
}
Upvotes: 2