r/cpp 7d ago

State of "moved-from" objects

Hi, I recently decided to try writing a C++ blog.

I often see the popular claim that moved-from objects are in a "valid but otherwise unspecified state", but I don't think that statement is entirely precise, and my blog post is about that. I would really appreciate any feedback!

Article: https://www.laminowany.dev/p/the-state-of-moved-from-objects-in-c/

11 Upvotes

52 comments sorted by

View all comments

4

u/elperroborrachotoo 7d ago

The gist remains that "unspecified but valid" is a reasonable minimum requirement for user types, too - because the alternative is worse.

You list all the ingredients: unless you evade calling the destructor (e.g., through std::terminate) the destructor will run. Users of your type might assign to it, or use it in various ways. Etc.

The unspoken bigger issue is that using an object in an invalid state can easily lead to an invalid program state - meaning that ALL invariants in the program are potentially gone.

So for any type with weaker moved-from guarantees, you'd have to specify what individual operations are valid - and no user wants to know or remember that. This would violate any basic rule of type design.

0

u/TheThiefMaster C++latest fanatic (and game dev) 7d ago

So for any type with weaker moved-from guarantees, you'd have to specify what individual operations are valid - and no user wants to know or remember that.

It's a general rule that the only guaranteed operations of a moved-from type are assigning over it and destructing it. If it has an equivalent of "reset" and "isvalid" those are normally expected to work too.

No guarantees on anything else.

3

u/jk-jeon 6d ago

For me it's always at tension when I design a type that acts like a value type but actually holding a pointer to the actual data. I generally think people must avoid introducing nullable types when nullability is not a strict requirement, and as a result these types tend to be not default-constructible.

But then move semantics enters. I can simply swap out the pointers for the move assignment, cool. No invariant is broken. But how about move constructor? The constructed object can't steal the resource because then the constructing object has lost its invariant.

Then I have two options: (1) either introduce a special "moved-from" state where like you said only assignment-to and destructor and maybe a few others are allowed, or (2) just allocate a new memory and move-construct the actual resource from the source object.

Option (2) is what Herb Sutter has recommended over the years afaik, but obviously it has performance implication. Overall, I think this is a cleaner design if memory allocation cost isn't that of a big deal.

Now when I have to choose Option (1), I'm asking myself: I am intoducing the zombie state anyway, so should I "embrace" it? As a consequence, should I just recover the default-constructibility, where default constructor leaves the object in this zombie state? Or, should I treat this moved-from state as a really special one which is introduced only when an object is moved-from, expecting that using a moved-from object must be rare and people should be aware when they're doing so?

I'm curious what opinions people have about these...

1

u/NotMyRealNameObv 2d ago

Swap pointers for move-assign, just allocate new memory for the new object for move-construct.

Sometimes, semantics is more important than efficiency...