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'm using MinGW, while running 'gcc --version' i get gcc 4.7.2
EDIT: for the first question see the comments in the question. It appears to be a bug in gcc.
The output of the code depends on which constructors are commented out. But i don't understand why the differences occur. What is the reason behind each output?
// 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 was why i started this test) - Let's say i have a real case with a large vector instead of the class MoveTester, how can i be sure the vector is moved instead of being copied in such cases?
The first part of the problem is an outdated compiler, but there's another one: you declared MoveTester::operator= in suboptimal way - it takes its argument by value, so a copy/move constructor is invoked 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'm getting the following output:
tester moved 
tester move assignment
tester move assignment
Perhaps you'll get something similar even with GCC 4.7.
Regarding your second question, the move constructor of std::vector is guaranteed by standard to have constant time complexity. The question is whether the compiler obeys the standard. I believe the only way to make sure is to debug or to profile your code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With