Make sure the move constructor is called

I have the following simplified code example:

#include <algorithm> #include <iostream> using namespace std; class ShouldBeMovedWhenSwapped { public: // ShouldBeMovedWhenSwapped() = default; // ShouldBeMovedWhenSwapped(ShouldBeMovedWhenSwapped&&) = default; // ShouldBeMovedWhenSwapped(const ShouldBeMovedWhenSwapped&) = default; // ShouldBeMovedWhenSwapped& operator=(ShouldBeMovedWhenSwapped&&) = default; struct MoveTester { MoveTester() {} MoveTester(const MoveTester&) { cout << "tester copied " << endl; } MoveTester(MoveTester&&) { cout << "tester moved " << endl; } MoveTester& operator=(MoveTester) { cout << "tester emplaced" << endl; return *this; } // must be declared if move declared }; MoveTester tester; }; int main() { ShouldBeMovedWhenSwapped a; ShouldBeMovedWhenSwapped b; std::swap(a,b); return 0; } 

I use MinGW, when I run 'gcc --version' I get gcc 4.7.2

EDIT : for the first question, see the comments in the question. This seems to be a bug in gcc.

The output of the code depends on which constructors are commented out. But I do not understand why differences arise. What is the reason for each exit?

 // Everything commented out tester moved tester copied <---- why not moved? tester emplaced tester copied <---- why not moved? tester emplaced // Nothing commented out tester moved tester moved tester emplaced tester moved tester emplaced // Move constructor commented out tester copied tester moved tester emplaced tester moved tester emplaced 

For my second question (which is why I started this test). Let them say that I have a real case with a large vector instead of the MoveTester class , how can I be sure that the vector is moved, and not copied in such cases?

+6
source share
1 answer

The first part of the problem is an outdated compiler, but there is one more: you declared MoveTester::operator= in a suboptimal form - it takes its argument by value, so the copy / move constructor is called in one extra time. Try this version of MoveTester :

 struct MoveTester { MoveTester() {} MoveTester(const MoveTester&) { cout << "tester copied " << endl; } MoveTester(MoveTester&&) { cout << "tester moved " << endl; } MoveTester& operator=(const MoveTester&) { cout << "tester copy assignment" << endl; return *this; } // must be declared if move declared MoveTester& operator=(MoveTester&&) { cout << "tester move assignment" << endl; return *this; } // must be declared if move declared }; 

I get the following output :

 tester moved tester move assignment tester move assignment 

You might get something similar even with GCC 4.7.


As for your second question, the std::vector move constructor is guaranteed by the standard to have constant time complexity. The question is whether the compiler obeys the standard. I believe that the only way to make sure that you need to debug or profile your code.

+4
source

All Articles