As I’ve asked in Move constructor/operator= and after a while I’ve agreed and accepted right answer to that question I was just thinking, if would it be useful to have something like “moving destructor” which would be invoked on moved object everytime we used move ctor or operator=.
In this way we would have to specify only in move dtor what we want from it and how our object shuld be nullified after being used by move constructor. Without this semantics it looks like everytime I write move ctor or operator= I have to explicitly state in each of them (code repetition/error introduction) how to nullify moved object which isn’t the best possible option I think. Looking forward to your opinions on this subject.
As I’ve asked in Move constructor/operator= and after a while I’ve agreed and accepted
Share
Could you bring a concrete example, where it would be useful. E.g, as far as I understand, move assignment might in the general case be implemented as
The swap method is probably beneficial in any case, if the class benefits from move semantics. This nicely delegates the work of releasing the old resources of
*thisto the regular destructor.Without particular examples that show a new kind of destructor is an elegant way of achieving correct code, your proposal doesn’t look very appealing.
Also, according to the latest revisions, move constructor / assignment operator can be defaulted. This means that very likely
my classes will look like this:
No destructor at all! What would make it appealing to me to have two destructors instead?
Also take into account that the assignment operator has old resources to deal with. As per current standard you have to be careful that normal destructor call is fine both after construction and assignment, and IMO, similarly with the proposed move destructor you would have to take care in the constructor and the assignment operator that the same move destructor can be safely called. Or would you like two move destructors – one for each? 🙂
Reworked example of the msdn example in the comments with move constructor/assignment
Some comments on the original MSDN sample:
1) checking for NULL before
deleteis unnecessary (perhaps it is done here for the output which I have stripped, perhaps it indicates a misunderstanding)2) deleting resources in the assignment operator: code reduplication. With the copy-and-swap idiom deleting previously held resources is delegated to the destructor.
3) copy-and-swap idiom also makes self-assignment checks unnecessary. It is not a problem if the resource is copied before it is deleted. – (“Copy the resource regardless” on the other hand only hurts when you expect lots of self-assignments done with this class.)
4) Assignment operator in the MSDN’s example lacks any kind of exception safety: if allocating new storage fails, the class is left in an invalid state with an invalid pointer. Upon destruction undefined behavior will happen.
This could be improved by carefully reordering the statements, and setting the deleted pointer to NULL in-between (unfortunately it seems that the invariant of this particular class is that it always holds a resource, so having it cleanly lose the resource in case of an exception isn’t perfect either). By contrast, with copy-and-swap, if an exception happens, left-hand value remains in its original state (much better, operation can’t be completed but data loss is avoidable).
5) The self-assignment check looks particularly questionable in the move assignment operator. I don’t see how left-hand-value could be the same as the right-hand-value in the first place. Would it take
a = std::move(a);to achieve identity (looks like it would be undefined behavior anyway?)?6) Again, move assignment is unnecessarily managing resources, which my version simply delegates to the regular destructor.
Conclusion: the code reduplication you are seeing is avoidable, it is only introduced by a naive implementation (one which you, for some reason, tend to see in tutorials, probably because code with reduplications is easier to follow for learners).
… if code reduplication is fine by you, otherwise reuse the destructor.
… or make sure you never delete anything before you are sure you can replace it.
Or rather a SO question: is it possible for self-assignment to happen in case of move assignment in a well-defined program.
Furthermore, from my draft (3092) I find that if a class has no user-defined copy constructor / assignment operator and nothing prevents the existence of a move-constructor / assignment, one will be declared implicitly as defaulted. If I’m not mistaken, this means: if the members are things like strings, vector, shared_ptrs etc, in which case you normally wouldn’t write a copy constructor / assignment, you’ll get a move constructor / move assignment for free.