Clear an object with a new object? - c++

I have:
MyClass myObject1( var1, var2 );
myObject1.someMethod(); //> Changes the interal state of the object
Now at some point I want to assign to myObject1 a "clean" object of type MyClass. Something like:
myObject1 = MyClass( otherVar1, otherVar2 );
Without using pointers (and/or unique_ptr) is there any fast/efficient way to do it?

Point 1. Don't worry about performance until you have data from your profiler indicating that you should. Doing otherwise is called premature optimization, and it's a bad thing. Choose the simplest design first.
Point 2. In C++11, you can write a move assignment operator for MyClass, if that makes sense in your case (hard to say without knowing the definition of MyClass).
However, an even better idea would be to use RAII wrappers such as unique_ptr as members of your class, and let the compiler-generated move assignment operator do a member-wise move and delegate the work to the move assignment operator of your members. Then, the move assignment operator of your unique_ptr would take care of doing The Right Thing.
This way you would not have to bother following the Rule of Three, Rule of Five, or whatnot, you would get optimal performance, and (as a bonus) exception-safety. Avoid defining your own special member functions, and get used to follow the Rule of Zero.
As mentioned by juanchopanza in the comments, in C++03 you could provide a no-throw swap() function - but again, that may or may not help depending on the definition of your class.

Related

Implementing move assignment in terms of destructor and move constructor

Say I have a class which manages memory and thus needs user-defined special member functions (imagine vector or similar).
Consider the following implementation of the move-assignment operator:
Class& operator=(Class&& rhs)
{
this->~Class(); // call destructor
new (this) Class(std::move(rhs)); // call move constructor in-place
}
Is it valid to implement a move-assignment operator this way? That is, does calling a destructor and constructor in this way not run afoul of any object lifetime rules in the language?
Is it a good idea to implement a move-assignment operator this way? If not, why not, and is there a better canonical way?
It's not valid: What if this move assignment is called as part of moving a child object? Then you destroy the child (assuming it has a virtual destructor) and recreate in its place a parent object.
I would say that even in a non-virtual context it's still a bad idea because you don't see the syntax very often and it may make the code harder to grok for future maintainers.
The best approach is to avoid having to write your own move constructor entirely (and using the default) by having all your class members take care of moving themselves. For example rely on unique_ptr, etc. Failing that it seems that implementing it in terms of swap (as the copy-and-swap for copy assignment) would be an easily understandable mechanism.
It may be valid(1). To address your specific issue about dtor/ctor lifetimes, yes that is valid(2). That is how the original implementation for vector worked.
It may be a good idea (it probably isn't), but you may not want a canonical way.(3)
(1) There is controversy about whether or moves need to be valid in the self-move case.
Arguing for self-move safety is the position that code should be safe (duh), we certainly expect self assignment to be safe. Also some user experience reports that for many algorithms which use move, self-move is possible and tedious to check for.
Arguing against self-move safety is the position that the whole point of move semantics is time savings and for that reason moves should be as fast as possible. A self-move check can be expensive relative to the cost of a move. Note that the compiler will never generate self-move code, because natural (not casted) rvalues can't be self-moved. The only way to have a self-move is if a "std::move()" cast is explicitly invoked. This puts the burden on the caller of std::move() to either verify that self-move isn't involved or convince themselves that it isn't. Note also that it would be trivial to create a user defined equivalent of "std::move" that checked for self-move and then did nothing. If you don't support self-move, you might want to document that.
(2) This is not a template so you can know if the expression "new (this) Class(std::move(rhs));" can throw. If it can, then no, this isn't valid.
(3) This code may be a puzzle to maintainers, who might expect a more traditional swap approach, but there is a potential drawbacks to the swap approach. If the resources being released by the target need to be released as soon as possible (such as a mutex), then swap has the drawback that the resources are swapped into the move source object. If the move is the result of a call to "std::move()" the move source object may not be immediately disposed of. (Since this isn't a template you can know what resources are being freed. If memory is the only resource being freed, then this isn't an issue.)
A better approach might be to factor out the resource freeing code from the destructor and the resource moving code from the move constructor and then just call those (inlined) routines in this move assignment operator.

In what scenarios should I expect to explicitly need to implement a move constructor and move assignment operator?

Given that a class actually is moveable, manually implementing the move constructor and move assignment operator for a class quickly become tedious.
I was wondering when doing so is actually a heavy, heavy, premature optimization?
For instance, if a class only has trivial POD data or members that themselves have move constructor and move assignment operator defined, then I'd guess that the compiler will either just optimize the shit out of the lot (in the case of PODs) and otherwise use the members' move constructor and move assignment operator.
But is that guaranteed? In what scenarios should I expect to explicitly need to implement a move constructor and move assignment operator?
EDIT: As mentioned below by Nicol Bolas in a comment to his answer at https://stackoverflow.com/a/9966105/6345, with Visual Studio 11 Beta (and before) no move constructor or move assignment operator is ever automatically generated. Reference: http://blogs.msdn.com/b/vcblog/archive/2011/09/12/10209291.aspx
If you find yourself implementing, any of:
destructor
copy constructor
copy assignment
Then you should be asking yourself if you need to implement move construction. If you "= default" any of the above, you should be asking yourself if you should then also "= default" the move members.
Even more importantly, you should be documenting and testing your assumptions, for example:
static_assert(std::is_nothrow_default_constructible<A>::value, "");
static_assert(std::is_copy_constructible<A>::value, "");
static_assert(std::is_copy_assignable<A>::value, "");
static_assert(std::is_nothrow_move_constructible<A>::value, "");
static_assert(std::is_nothrow_move_assignable<A>::value, "");
static_assert(std::is_nothrow_destructible<A>::value, "");
First, move semantics only help for classes that hold resources of any kind. "Flat" classes don't benefit from it at all.
Next, you should build your classes out of "building blocks", like vector, unique_ptr and the likes, that all deal with the nitty-gritty low-level detail of resources. If your class is done as such, you won't have to write anything at all since the compiler will generate the members correctly for you.
If you need to write a destructor for, say, logging, generation of move ctors will be disabled, so you need a T(T&&) = default; for compilers that support it. Otherwise, this is one of the only places were to write such a special member yourself (well, except if you write such a "building block").
Note that the logging in the destructor and constructor can be done an easier way. Just inherit from a special class that logs on construction / destruction. Or make it a member variable. With that:
tl;dr Let the compiler generate the special member for you. This also counts for copy constructor and assignment operator, aswell as the destructor. Don't write those yourself.
(Okay, maybe the assignment operators, if you can identify them as a bottle neck and want to optimize them, or if you want special exception safety or somesuch. Though, the "building blocks" should already provide all that.)
Do it every time the default behavior is undesirable or every time the default ones have been deleted and you still need them.
The compiler default behavior for move is call the member and base move. For flat classes / buil-in types this is just like copy.
The problem is typically present with classes holding pointers or value representing resources (like handle, or particular indexes etc) where a move requires to copy the values in the new place, but also to set the old place to some "null state value" recognizable by the destructor. In all other cases, the default behavior is OK.
The problem may also arise when you define a copy (and the compiler deletes the default move) or a move (and the compiler deletes the default copy), and you need them both. In these cases, re-enabling the default may suffice.
In what scenarios should I expect to explicitly need to implement a move constructor and move assignment operator?
Under the following cases:
When you are using Visual Studio 10 or 11. They implement r-value references, but not compiler generated move semantics. So if you have a type that has members that need moving or even contains a moveable type (std::unique_ptr, etc), you must write the move yourself.
When you might need copy constructors/assignment operators and/or a destructor. If your class contains something that made you manually write copy logic or needs special cleanup in a destructor, odds are good that you'll need move logic too. Note that this includes deleting copy mechanisms (Type(const Type &t) = delete;). If you don't want to copy the object, then you probably need move logic or to delete the move functions too.
As others have said, you should try to keep the number of types that need explicit move or copy mechanisms to a bare minimum. Put these in utility "leaf" classes, and have most of your classes rely on the compiler-generated copy and move functions. Unless you're using VS, where you don't get those...
Note: a good trick with move or copy assignment operators is to take them by value:
Type &operator=(Type t) { std::swap(*this, t); return *this; }
If you do this, it will cover both move and copy assignment in one function. You still need separate move and copy constructors, but it does reduce the number of functions you have to write to 4.
The downside is that you're effectively copying twice if Type is made of only basic types (first copy into the parameter, second in swap). Of course, you have to implement/specialize swap, but that's not difficult.
I'm sorry. I may have missed the point of your question. I'm taking your question to mean copy constructors.
Back in the 1990s when I learned C++, I was taught always to write a copy constructor when designing a class. Otherwise, and this may have changed with newer versions of the compiler, C++ will generate a copy constructor for you in the situations that require one.
That default copy constructor may not always work the way you want. This would especially be true if your class contains pointers, or you otherwise do not want the default byte-wise copy of a default copy constructor.
Finally, I was taught that by writing a copy constructor, you are taking exact control over how you want your class copied.
I hope this helps.

Under what conditions should I be thinking about implementing a move constructor and a move operator?

For standard copy constructors and assignment operators, I always think about implementing them or deleteing the defaults out of existence, if my class implements a destructor.
For the new move constructor and move operator, what is the right way to think about whether or not an implementation is necessary?
As a first pass of transitioning a system from pre-C++0x, could I just delete the default move constructor and move operator or should I leave them alone?
You don't have to worry about it, in the sense that when you user-declare a destructor (or anything else listed in 12.8/9), that blocks the default move constructor from being generated. So there's not the same risk as there is with copies, that the default is wrong.
So, as the first pass leave them alone. There may be places in your existing code where C++11 move semantics allow a move, whereas C++03 dictates a copy. Your class will continue to be copied, and if that caused no performance problems in C++03 then I can't immediately think of any reason why it would in C++11. If it did cause performance problems in C++03, then you have an opportunity to fix a bug in your code that you never got around to before, but that's an opportunity, not an obligation ;-)
If you later implement move construction and assignment, they will be moved, and in particular you'll want to do this if you think that C++11 clients of your class are less likely to use "swaptimization" to avoid copies, more likely to pass your type by value, etc, than C++03 clients were.
When writing new classes in C++11, you need to consider and implement move under the same criteria that you considered and implemented swap in C++03. A class that can be copied implements the C++11 concept of "movable", (much as a class that can be copied in C++03 can be swapped via the default implementation in std), because "movable" doesn't say what state the source is left in - in particular it's permitted to be unchanged. So a copy is valid as a move, it's just not necessarily an efficient one, and for many classes you'll find that unlike a "good" move or swap, a copy can throw.
You might find that you have to implement move for your classes in cases where you have a destructor (hence no default move constructor), and you also have a data member which is movable but not copyable (hence no default copy constructor either). That's when move becomes important semantically as well as for performance.
With C++11, you very rarely need to provide a destructor or copy semantics, due to the way the library is written. Compiler provided members pretty much always do fine (provided they are implemented correctly: MSVC forces you to implement a lot of move semantics by hand, which is very bothersome).
In case you have to implement a custom destructor, use the following approach:
Implement a move constructor, and an assignment operator taking by value (using copy&swap: note that you cannot use std::swap since it uses the assignment. You have to provide a private swap yourself). Pay attention to exception guarantees (look up std::move_if_noexcept).
If necessary, implement a copy constructor. Otherwise, delete it. Beware that non default copy semantics rarely make sense.
Also, a virtual destructor counts as a custom destructor: provide or delete copy + move semantics when declaring a virtual destructor.
Since they are used as an optimization you should implement them if the optimization is applicable to your class. If you can "steal" the internal resource your class is holding from a temporary object that is about to be destroyed. std::vector is a perfect example, where move constructor only assigns pointers to internal buffer leaving the temporary object empty (effectively stealing the elements).

Rule of three with smart pointer?

I'm a little confused by using "rule of three" with smart pointers. If I have a class whose only data member is a smart pointer, do I need to explicitly define destructor, copy constructor, and assignment operator?
My understanding is that since smart pointer will handle the resource automatically, then I don't need to explicitly define destructor, and thus I shouldn't need to do so for the other two based on rule of three. However, I'm not sure if the default copy constructor is good enough for smart pointers such as shared_ptr.
Thank you for your help!
The default destructor is fine, because the destructor of shared_ptr will take care of the deallocation of the object. The default copy constructor may be acceptable depending on your purposes: when you copy the object that owns the shared_ptr, the copy will share ownership with the original. The same would naturally be true of the default assignment operator. If that’s not what you want, define a copy constructor that does otherwise—for instance, that clones the referenced object.
In short, "no". The whole point of factoring code into single-responsibility classes is that you can compose your classes from "smart" building blocks so that you don't have to write any code at all.
Consider the following:
class Foo
{
std::shared_ptr<Bar> m_pbar;
std::string m_id;
};
This class automatically has copy and move constructors and copy and move assignment operators that are as good as they can get, and everything is taken care of.
If you want to be extreme, you could say that in most cases you should probably never be writing a destructor or copy constructor at all -- and if you do, then perhaps you should best factor that functionality into a separate class with one single responsibility.
The rule of three actually says:
If you need to define a non-trivial version of any of the following:
Destructor
Assignment Operator
Copy Constructor
...then you probably need the other two as well.
You seem to be interpreting it as:
If you need a non-trivial destructor then you also need the other two.
But that's not quite the same thing, is it?

Would this constructor be acceptable practice?

Let's assume I have a c++ class that have properly implemented a copy constructor and an overloaded = operator. By properly implemented I mean they are working and perform a deep copy:
Class1::Class1(const Class1 &class1)
{
// Perform copy
}
Class1& Class1::operator=(const Class1 *class1)
{
// perform copy
return *this;
}
Now lets say I have this constructor as well:
Class1::Class1(Class1 *class1)
{
*this = *class1;
}
My question is would the above constructor be acceptable practice? This is code that i've inherited and maintaining.
I would say, "no", for the following reasons:
A traditional copy constructor accepts its argument as a const reference, not as a pointer.
Even if you were to accept a pointer as a parameter, it really ought to be const Class1* to signify that the argument will not be modified.
This copy constructor is inefficient (or won't work!) because all members of Class1 are default-initialized, and then copied using operator=
operator= has the same problem; it should accept a reference, not a pointer.
The traditional way to "re-use" the copy constructor in operator= is the copy-and-swap idiom. I would suggest implementing the class that way.
Personally, I don't think it's good practice.
For the constructor, it's hard to think of a place where an implicit conversion from a pointer to an object to the object itself would be useful.
There's no reason for the pointer to be to non-const, and if you have available pointer to the class it is not hard to dereference it, and so clearly state your intention of wanting to copy the object using the copy constructor.
Similarly, for the non-standard assignment operator why allow assignment from a pointer when correctly dereferencing at the call site is clearer and more idiomatic?
I believe a somewhat more important issue than what has been discussed so far is that your non-standard assignment operator does not stop the compiler from generating the standard one. Since you've decided that you need to create an assignment operator (good bet since you made the copy constructor), the default is almost certainly not sufficient. Thus a user of this class could fall prey to this problem during what would seem very basic and standard use of an object to almost anyone.
Objects and pointers to objects are two very different things. Typically, when you're passing objects around, you expect that they're going to be copied (though, ideally functions would take const refs where possible to reduce/eliminate unnecessary copies). When you're passing a pointer around, you don't expect any copying to take place. You're passing around a pointer to a specific object and, depending on the code, it could really matter that you deal with that specific object and not a copy of it.
Assignment operators and constructors that take pointers to the type - especially constructors which can be used for implicit conversion - are really going to muddle things and stand a high chance of creating unintended copies, which not only could be a performance issue, but it could cause bugs.
I can't think of any good reason why you would ever want to make the conversion between a pointer to a type and the type itself implicit - or even explicit. The built-in way to do that is to dereference the object. I suppose that there might be some set of specific circumstances which I can't think of where this sort of thing might be necessary or a good idea, but I really doubt it. Certainly, I would strongly advise against doing it unless you have a specific and good reason for doing so.