8

Consider this code

Foo f1;
Foo f2{ std::move(f1) };

I would expect the member values of f1 to no longer necessarily hold the values given by the default constructor. However, testing with multiple compilers using this implementation of Foo suggests otherwise.

class Foo
{
public:
    Foo() = default;
    Foo(Foo &&) = default;

    std::string s{ "foo" };
    bool t{ true };
    bool f{ false };
};

After the move f1.t is always true and f1.f is always false. As described in this question I would expect the values to either be nondeterministic or that both boolean values would have the same value. However, they seem to get the same value they would get from the default constructor.

Live example with GCC

Is this just a implementation details of my compilers (by coincidence the same) or is this in the standard?

Community
  • 1
  • 1
Mathias
  • 1,446
  • 2
  • 16
  • 31
  • 2
    "I would expect the member values of f1 to be uninitialized now" You can't uninitialize something that has already been initialized. – juanchopanza Mar 18 '16 at 22:30
  • You can move something uninitialized into its place: http://cpp.sh/5yxdt – Mathias Mar 18 '16 at 23:08
  • No, that would be undefined behaviour (reading from uninitialized variables.) But your example doesn't show that. – juanchopanza Mar 18 '16 at 23:09
  • Yes, maybe I'm not sure about this. Are you saying: 1) That last line is undefined behaviour because `initialized` is not initialized. Or 2) That last line is ok because `initialized` is in fact initialized? If 2) When was it initialized to ""? – Mathias Mar 18 '16 at 23:19
  • `initialized` is initialized to such that `initialized.state` is `std::string("")`. – juanchopanza Mar 18 '16 at 23:20
  • So `movedto.state` is initialized to "" before entering the move constructor for `movedto`? – Mathias Mar 18 '16 at 23:22
  • 3
    No, it is only initialized once. The move constructor leverages `std::string`'s move constructor, which takes the state out of `initialized.state`. This happens to be a string equivalent to ""` – juanchopanza Mar 18 '16 at 23:29

1 Answers1

11

After the move f1.t is always true and f1.f is always false.

For the fundamental types, moving is copying. You wouldn't want your implementation to copy the bool AND zero out the old one - that's unnecessary extra work. In a simple POD, moving would just be a memcpy - but if what you're suggesting would happen, you'd also have to then do a memset. Much faster to just do nothing.

Is this just a implementation details of my compilers (by coincidence the same) or is this in the standard?

This is in the standard in [class.copy]:

The implicitly-defined copy/move assignment operator for a non-union class X performs memberwise copy- /move assignment of its subobjects. [...] Each subobject is assigned in the manner appropriate to its type:
— [...]
— if the subobject is of scalar type, the built-in assignment operator is used.

Barry
  • 286,269
  • 29
  • 621
  • 977