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?
Related
I know about the rule of five which states that if you implement a destructor, you should most likely also implement a copy constructor, copy assignment operator, a move constructor and a move assignment operator.
However if I implement a move operator, do I absolutely have to implement a copy counterpart, or is it just best practice?
The "Rule of Zero" may be applicable to your situation. Why are you providing a move constructor or move assignment operator in the first place? Is it because your class represents unique ownership of some resource? If so, it may be better to encapsulate ownership of that resource in a unique_ptr member or something similar. Then, you don't need to write the move constructor and move assignment operator anymore. The compiler will generate them automatically, which will move the unique_ptr member and thus transfer ownership. The compiler will also ensure that the class is not copyable.
OK, but let's say that for some reason the Rule of Zero is not appropriate to your class. What will happen if you declare only a move constructor? Then, the compiler will implicitly disable copying for your class, which will mean that objects of your class type can only be initialized from rvalues of the same type, and not from lvalues. The Rule of Five tells you that it is better to be explicit about this situation instead of leaving it to the reader to guess what the compiler is doing. So, it is best practice (but not required) to define the copy constructor as = delete;.
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.
I recently read, Rule of three and am wondering if I am violating it?
In my GUI application, classes like MainFrame, Interface, Circuit, Breadboard etc. (class name are indicative) have a single instance of each of them. In their constructors, I have allocated some resources (memory), which I safely release in their destructors.
So I have defined only destructor, but not copy constructor and assignment operator.
I am sure I don't need them, but I am curious if I am violating the rule, and what can/should I do to follow it?
The rule of three is about dealing with all the Big Three, but that does not necessarily mean you'll have to define them if you don't want to. Either you provide them or you forbid them. What you shouldn't do is ignore them.
So I have defined only destructor, but not copy constructor and copy operator.
Am I violating Rule of three?
Yes, you are in violation of the rule. The compiler will generate a copy constructor and copy assignment operator, and since you allocate memory in the constructor and release in the destructor, these copies will have wrong semantics: they'll copy the pointers, and you will have two classes aliasing the same memory. The assignment won't even release the old memory, and simply overwrite the pointer.
Is this a problem?
If, like you imply, you don't make copies or assign to instances of those classes, nothing will go wrong. However, it's better to be on the safe side and declare (and don't even bother defining) the copy constructor and copy assignment operator private, so you don't invoke them accidentally.
In C++11 you can use the = delete syntax instead:
T(T const&) = delete; // no copy constructor
T& operator=(T const&) = delete; // no copy assignment
It depends a lot on you application logic and how the you have documented your interface classes to the users.
Normally, a good c++ programmer must be aware of rule of three (and a half if you know the "copy and swap idiom") and 5 and a 1/2 in case of c++11 (Move semantics).
If you class manages resource and if the same class is copyable (i.e copy ctor and assigment operator not defined as private) then its very important to do deep copying by writing your own copy ctor and assignment operator.
But If you are always toying your class by passing them as REFERENCE then better define a default copy ctor and assignment operator as private so that even if you pass by valy or copy by mistake, the compiler would warn you.
You should declare (but not implement) a private copy constructor and assignment operator. Make sure you don't implement the functions. This will prevent any kind of copying of classes not supposed to be copied.
Yes, it does violate the rule of three as per that definition.
It is, however, a "rule of thumb". A general guideline. If you don't need copy construction or assignment operations, don't implement them. Others have suggested declaring them as private and defining them as empty. I'd go one step further and say don't even define them.
If you define them, then you could potentially still invoke the empty methods. Instead, leave them undefined and, if you ever try to invoke those methods, you will receive a linker error because the method definitions could not be found. Favor build-time errors over run-time errors/undesired behavior.
If you don't need it, don't follow it. The motivation behind the rule of three is that, when you need a destructor, that is usually because you need to do some dynamic deallocations.
If you do deallocations as well, you're going to need the copy constructor and assignment operators as well. Imagine you have a class that has a pointer to something:
struct Foo
{
Foo() { ptr_ = new int; }
~Foo() { delete ptr_; }
int* ptr_;
};
Because you don't define a copy constructor and an assignment operator, whenever you make a copy of a Foo, both the original and the copy will use a pointer to the same int; when either the original or the copy gets destroyed, the pointer is freed, leaving the other with unusable data.
Foo(cont Foo& other) {
other.ptr_ = new int(*ptr_);
}
// Same for operator=
If you don't do any dynamic allocations in your constructor/ destructor, there's a good chance you don't actually need a copy constructor or an assignment operator (but not necessarily).
When is a class implicitly copied in C++?
I have a class that contains a unique_ptr, and therefore cannot be safely copied, and therefore, I disabled the copy constructor on the class by creating private versions of X(X&) and X& operator = X&.
I immediately ran into the problem that instances of this class cannot be returned, because returning actually makes a copy of the instance.
Are there any other situations I need to watch out for?
Returning does not copy the instance, it moves the instance. You just forgot to provide a move constructor. In addition, classes are now moved when used in Standard containers in most situations in which they used to be copied.
In short, provide a move constructor and move assignment operator (and swap, preferably) and you should find that almost all situations where copies are implicit, they're now moves.
The situations that come to mind are: functions that receives the class by value, functions that returns then class by value, and any class or container that contains that class. Classes like std::vector will use move semantics whenever possible (you did overload that right)? but will be unable to use functions that require a copy constructor, such as copying the vector. As GMan said though, you can make a copy constructor for your class, and do a deep copy of the std::unique_ptr manually, if you want to make things easier.
This question already has answers here:
What is The Rule of Three?
(8 answers)
Closed 10 years ago.
Say I've got a class where the sole data member is something like std::string or std::vector. Do I need to provide a Copy Constructor, Destructor and Assignment Operator?
In case your class contains only vector/string objects as its data members, you don't need to implement these. The C++ STL classes (like vector, string) have their own copy ctor, overloaded assignment operator and destructor.
But in case if your class allocates memory dynamically in the constructor then a naive shallow copy will lead to trouble. In that case you'll have to implement copy ctor, overloaded assignment operator and destructor.
The usual rule of thumb says: if you need one of them, then you need them all.
Not all classes need them, though. If you class holds no resources (memory, most notably), you'll be fine without them. For example, a class with a single string or vector constituent doesn't really need them - unless you need some special copying behavior (the default will just copy over the members).
The default copy constructor will copy the vector if it is declared by value. Beware if you stored pointers in your vector, in such a case, you need to provide specific behaviour for copy/assignement/destruction to avoid memory leaks or multiple delete.
I can think of a few cases when you need to write your own Big Three. All standard containers know how to copy and destroy themselves, so you don't necessarily need to write them. Here's how to know when you do:
Does my class own any resources?
The default copy semantics for pointers is to copy the value of the pointer, not what it points to. If you need to deep copy something, even if it's stored inside a standard container, you need to write your own copy constructor and assignment operator. You also need to write your own destructor to properly free those resources.
Might someone inherit from my class?
Base classes need a destructor. Herb Sutter recommends making them either public and virtual (most common case) or protected and non-virtual, depending on what you want to do with them. The compiler-generated destructor is public and non-virtual, so you'll have to write your own, even if it doesn't have any code in it. (Note: this doesn't imply you have to write a copy constructor or assignment operator.)
Should I prevent a user from copying objects of my class?
If you don't want the user to copy your objects (maybe that's too expensive), you need to declare the copy constructor and assignment operators either protected or private. You don't have to implement them unless you need them. (Note: this doesn't imply you have to write a destructor.)
Bottom line:
The most important thing is to understand what the compiler-generated copy constructor, assignment operator, and destructor will do. You don't need to be afraid of them, but you need to think about them and decide if their behavior is appropriate for your class.
No but there are a number of reasons why you shouldn't allow the compiler to auto generate these functions.
In my experience it is always best to define them yourself, and to get into the habit of making sure that they are maintained when you change the class. Firstly you may well want to put a breakpoint on when a particular ctor or dtor is called. Also not defining them can result in code bloat as the compiler will generate inline calls to member ctor and dtor (Scott Meyers has a section on this).
Also you sometimes want to disallow the default copy ctors and assignments. For example I have an application that stores and manipulates very large blocks of data. We routinely have the equivalent of an STL vector holding millions of 3D points and it would be a disaster if we allowed those containers to be copy constructed. So the ctor and assignment operators are declared private and not defined. That way if anyone writes
class myClass {
void doSomething(const bigDataContainer data); // not should be passed by reference
}
then they'll get a compiler error. Our experience is that an explicit become() or clone() method is far less error prone.
So all in all there are many reason to avoid auto generated compiler functions.
those container will need a "copy constructible" element, and if you don't supply the copy constructor, it will call default copy constructor of your class by deducing from your class members (shallow copy).
easy explanation about default copy constructor is here : http://www.fredosaurus.com/notes-cpp/oop-condestructors/copyconstructors.html
it is so with destructor, the container need to have access to your destructor or your default class destructor if you don't provides one (ie. it will not work if you declare your destructor as private )
you need to provide them if you need them. or possible users of your classes. destructor is always a must, and copy constructors and assignment operator are automatically created by compiler. (MSVC at least)
When ever you have a class that requires deep copies, you should define them.
Specifically, any class which contains pointers or references should contain them such as:
class foo {
private:
int a,b;
bar *c;
}
Subjectively, I would say always define them, as the default behavior provided by the compiler generated version may not be what you expect / want.
Not for strings or vectors, since the trivial constructors / destructors etc, will do fine.
If your class has pointers to other data and need deep copies, or if your class holds a resource that has to be deallocated or has to be copied in a special way.