Re: Implicit move constructor rules in c++0x still badly broken?
On Feb 22, 2:04 pm, George Ryan <george.r...@gmail.com> wrote:
On Feb 21, 5:40 pm, Howard Hinnant <howard.hinn...@gmail.com> wrote:
The ironic thing is that the link you site has not yet offered a code
example that gets broken.
Unless I am mistaken, I haven't seen how the Abraham's code in the
original post isn't broken. (This example is listed in the comments).
The InvariantChecker that checks the state of another object in its
destructor will fail because of an implicit move because it silently
working on an object that is no longer valid.
This code would have worked under the existing standard, and will
break under the new one.
What's even stranger is whether the invariant will or won't pass also
depends on whether or not someone adds or removes a user-defined
destructor somewhere else.
Here's Dave's code, completed and instrumented:
#include <iostream>
class Y
{
int state_;
public:
enum {destructed = -2, moved_from, default_constructed};
Y() : state_(default_constructed) {}
Y(const Y& a) : state_(a.state_) {}
Y& operator=(const Y& a) {state_ = a.state_; return *this;}
Y(Y&& a) : state_(a.state_)
{
a.state_ = moved_from;
}
Y& operator=(Y&& a)
{
state_ = a.state_;
a.state_ = moved_from;
return *this;
}
~Y()
{
state_ = destructed;
}
explicit Y(int s) : state_(s) {}
friend
std::ostream&
operator<<(std::ostream& os, const Y& a)
{
switch (a.state_)
{
case Y::destructed:
os << "Y is destructed\n";
break;
case Y::moved_from:
os << "Y is moved from\n";
break;
case Y::default_constructed:
os << "Y is default constructed\n";
break;
default:
os << "Y = " << a.state_ << '\n';
break;
}
return os;
}
friend bool operator==(const Y& x, const Y& y)
{return x.state_ == y.state_;}
friend bool operator<(const Y& x, const Y& y)
{return x.state_ < y.state_;}
};
class InvariantChecker
{
Y* v_;
InvariantChecker(const InvariantChecker&);
InvariantChecker& operator=(const InvariantChecker&);
public:
explicit InvariantChecker() : v_(0) {}
explicit InvariantChecker(Y& v) : v_(&v) {}
~InvariantChecker()
{
if (v_)
std::cout << *v_ << '\n';
}
};
Y
f(bool choose)
{
Y a(1), b(2);
InvariantChecker xa(a), xb(b);
// Incorrect comment follows:
// The use of ?: guarantees that there will be no copy elision.
// Instead, either a or b will be *moved* into the return value.
return choose ? a : b;
// xb and xa get destroyed here
// b and a get destroyed thereafter
}
int main()
{
Y y = f(true);
}
Using a recent build of clang and libc++ this, at least for me
outputs:
Y = 2
Y = 1
Using g++-4.4 with libc++ I get the identical output. To demonstrate
Dave's point I expect to see:
Y is moved from
in the output. If someone copy/pastes this code into another
environment and gets different results, please post that.
Again (emphasis), I'm not claiming that Dave's code can't be made to
demonstrate Dave's complaint. I just think it would be a good idea if
we discussed (and tested) actual code.
-Howard
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]