I've read that The Rule of Three, What is The Rule of Three? is summarized as follows:
If you need to explicitly declare either the destructor, copy constructor or copy assignment
operator yourself, you probably need to explicitly declare all three of them.
My question is: In a C++ application, I have a class that manages resources (has a destructor that handles deleting pointers). I know that the application uses assignment operator all over the place, but I am absolutely certain that there is no usage in the application of a copy constructor, i.e., usage of the type Class c(..); Class d(c); so under these circumstances, am I still required to implement both an assignment operator and a copy constructor? Or will an assignment operator alone suffice? Is it possible that the assignment operator uses the copy constructor somehow?
Appreciate your thoughts.
If you know that the copy constructor won't be used, you can express that by making it private and unimplemented, thus:
class C
{
private:
C(const C&); // not implemented
};
(in C++11 you can use the new = delete syntax). That said, you should only do that if you're absolutely sure it will never be needed. Otherwise, you might be better off implementing it. It's important not to just leave it as is, as in that case the compiler will provide a default memberwise copy constructor that will do the wrong thing - it's a problem waiting to happen.
To some extent it depends on what the class is going to be used for - if you're writing a class that's part of a library, for instance, it makes much more sense to implement the copy constructor for consistency reasons. You have no idea a priori how your class is going to be used.
I am absolutely certain that there is no usage in the application of a copy constructor, i.e., usage of the type Class c(..); Class d(c)
Are you aware that the following code
Foo c;
Foo b = c;
invokes the copy constructor and NOT the assignment operator? I'd implement the copy constructor just to be safe.
In almost all cases, the compiler will generate these methods for you and you don't need to do anything. But, if implicitly generated copy constructor/assignment operator won't do what you want, and design-wise your class makes sense to be able to be copied, you should explicitly provide a copy ctor and assignment operator whether you use them both or not (as good practice).
If, design-wise, your class makes sense to be noncopyable, you can declare but not define the copy ctor/assignment op.
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;.
I've read that The Rule of Three, What is The Rule of Three? is summarized as follows:
If you need to explicitly declare either the destructor, copy constructor or copy assignment
operator yourself, you probably need to explicitly declare all three of them.
My question is: In a C++ application, I have a class that manages resources (has a destructor that handles deleting pointers). I know that the application uses assignment operator all over the place, but I am absolutely certain that there is no usage in the application of a copy constructor, i.e., usage of the type Class c(..); Class d(c); so under these circumstances, am I still required to implement both an assignment operator and a copy constructor? Or will an assignment operator alone suffice? Is it possible that the assignment operator uses the copy constructor somehow?
Appreciate your thoughts.
If you know that the copy constructor won't be used, you can express that by making it private and unimplemented, thus:
class C
{
private:
C(const C&); // not implemented
};
(in C++11 you can use the new = delete syntax). That said, you should only do that if you're absolutely sure it will never be needed. Otherwise, you might be better off implementing it. It's important not to just leave it as is, as in that case the compiler will provide a default memberwise copy constructor that will do the wrong thing - it's a problem waiting to happen.
To some extent it depends on what the class is going to be used for - if you're writing a class that's part of a library, for instance, it makes much more sense to implement the copy constructor for consistency reasons. You have no idea a priori how your class is going to be used.
I am absolutely certain that there is no usage in the application of a copy constructor, i.e., usage of the type Class c(..); Class d(c)
Are you aware that the following code
Foo c;
Foo b = c;
invokes the copy constructor and NOT the assignment operator? I'd implement the copy constructor just to be safe.
In almost all cases, the compiler will generate these methods for you and you don't need to do anything. But, if implicitly generated copy constructor/assignment operator won't do what you want, and design-wise your class makes sense to be able to be copied, you should explicitly provide a copy ctor and assignment operator whether you use them both or not (as good practice).
If, design-wise, your class makes sense to be noncopyable, you can declare but not define the copy ctor/assignment op.
I know why to make default constructor and copy constructor private to implement singleton class in C++. But what I don't understand is that why make copy assignment operator private, because there will not be two existing objects to start with.
My exploration brings two points:
According to Alexandrescu in "Modern C++ Design", the assignment
operator to be made private to prevent self-assignment.
Second, according to rule of three, if you define one of ctor,
copy ctor and assignment operator for a class, you should define
explicitly all three. So, is it a matter of following this rule
only.
So, what's your take on this?
I think, the need to prohibit the assignment is more in semantic considerations: as singleton is unique, the assignment for it doesn't have any sense. So if it would be even technically possible to implement assignment in a reasonable way, logically you need to prohibit it anyway.
So exactly because there must be never a need to copy a singleton, the operation has to be prohibited. Otherwise there is a room for confusion and mistakes: the developers will try to use it if it's allowed (and wonder what's wrong).
The good design minimizes the amount of WTFs.
No.
In a Singleton you want to manage all possible construction, assignment and destruction. By making all those operations private you actually just prevent others from using them.
Also note that typically copy construction and copy assignment will be declared private to prevent invocation from outside but will not be defined because they are not used in practice... and so if they were the linker would complain.
In C++11 you would declare copy construction and copy assignment as deleted.
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).
Considering the high quality of today's compilers regarding return value optimization (both RVO and NRVO), I was wondering at what class complexity it's actually meaningful to start adding move constructors and move assignment operators.
For instance, for this really_trivial class, I just assume that move semantics cannot offer anything more than RVO and NRVO already does when copying around instances of it:
class really_trivial
{
int first_;
int second_;
public:
really_trivial();
...
};
While in this semi_complex class, I'd add a move constructor and move assignment operator without hesitation:
class semi_complex
{
std::vector<std::string> strings_;
public:
semi_complex(semi_complex&& other);
semi_complex& operator=(semi_complex&& other);
...
};
So, at what amount and of what kinds of member variables does it start making sense to add move constructors and move assignment operators?
It is already meaningful for purely semantic reasons, even if you keep the optimization-aspects out completely. Just imagine the case where a class does not/cannot implement copying. For example boost::scoped_ptr cannot be copied, but it can be moved!
In addition to the excellent answers already given, I would like to add a few forward-looking details:
There are new rules in the latest C++0x draft for automatically generating a move constructor and move assignment operator. Although this idea is not entirely new, the latest rules have only been in the draft since Oct. 2010, and not yet widely available in compilers.
If your class does not have a user-declared copy constructor, copy assignment operator, move constructor, move assignment operator and destructor, the compiler will provide defaulted move constructor and move assignment operator for you. These default implementations will simply member-wise move everything.
You can also explicitly default your move members:
semi_complex(semi_complex&&) = default;
semi_complex& operator=(semi_complex&&) = default;
Note that if you do so, you will implicitly inhibit copy semantics unless you explicitly supply or default the copy constructor and copy assignment operator.
In a closely related late-breaking change: If your class has an explicit destructor, and implicit copy members, the implicit generation of those members is now deprecated (the committee would like to remove the implicit generation of copy when there is an explicit destructor, but can't because of backwards compatibility).
So in summary, any time you have a destructor declared, you should probably be thinking about explicitly declaring both copy and move members.
As a rule of thumb I would say add a move constructor whenever you have member variables which hold (conditionally) dynamically allocated memory. In that case its often cheaper if you can just use the existing memory and give the move source the minimal allocation it needs so it can still function (meaning be destroyed). The amount of member variables doesn't matter that much, because for types not involving dynamic memory its unlikely to make a difference whether you copy or move them (even the move constructor will have to copy them from one memory location to another somehow).
Therefore move semantices make sense, when
dynamic memory allocation is involved
move makes sense for one or more member variables (which means those involve dynamic allocation somewhere along the line).
Typically, moving makes sense when the class holds some kind of resource, where a copy would involve copying that resource and moving would not. The easiest example is dynamically allocated memory. However, it is worth noting that the compiler will automatically generate move constructors and operators, just like it will for copying.
Irrespective of anything that might be automatically done by the compiler I'd say that:
If any member has meaningful and beneficial move semantics, that the class should have this move semantics too. (-> std::vector members)
If any dynamic allocations are involved when copying, move operations make sense.
Put otherwise, if move can do something more efficiently than copy, it makes sense to add it. In your really_trivial a move could only be as efficient as the copy already is.