To my understand these semantics are used only with the copy constructor, moving constructor, copy assignment, moving assignment, and the destructor. Using = delete is for prohibiting the use of one of the functions, and that = default is used if you want to be explicit to the compiler on where to use the defaults for these functions.
What are the best practices when using these keywords while making a class? Or rather how do I keep mindful of these when developing a class?
For example, if I don't know whether I'll use one of these functions, is it better to prohibit it with delete or allow it and use default?
Good question.
Also important: Where to use = default and = delete.
I have somewhat controversial advice on this. It contradicts what we all learned (including myself) for C++98/03.
Start your class declaration with your data members:
class MyClass
{
std::unique_ptr<OtherClass> ptr_;
std::string name_;
std::vector<double> data_;
// ...
};
Then, as close as is practical, list all of the six special members that you want to explicitly declare, and in a predictable order (and don't list the ones you want the compiler to handle). The order I prefer is:
destructor // this tells me the very most important things about this class.
default constructor
copy constructor // I like to see my copy members together
copy assignment operator
move constructor // I like to see my move members together
move assignment operator
The reason for this order is:
Whatever special members you default, the reader is more likely to understand what the defaults do if they know what the data members are.
By listing the special members in a consistent place near the top, and in a consistent order, the reader is more likely to quickly realize which special members are not explicitly declared ‐ and thus either implicitly declared, or not do not exist at all.
Typically both copy members (constructor and assignment) are similar. Either both will
be implicitly defaulted or deleted, explicitly defaulted or deleted, or explicitly supplied. It is nice to confirm this in two lines of code right next to each other.
Typically both move members (constructor and assignment) are similar...
For example:
class MyClass
{
std::unique_ptr<OtherClass> ptr_;
std::string name_;
std::vector<double> data_;
public:
MyClass() = default;
MyClass(const MyClass& other);
MyClass& operator=(const MyClass& other);
MyClass(MyClass&&) = default;
MyClass& operator=(MyClass&&) = default;
// Other constructors...
// Other public member functions
// friend functions
// friend types
// private member functions
// ...
};
Knowing the convention, one can quickly see, without having to examine the entire class declaration that ~MyClass() is implicitly defaulted, and with the data members nearby, it is easy to see what that compiler-declared and supplied destructor does.
Next we can see that MyClass has an explicitly defaulted default constructor, and with the data members declared nearby, it is easy to see what that compiler-supplied default constructor does. It is also easy to see why the default constructor has been explicitly declared: Because we need a user-defined copy constructor, and that would inhibit a compiler-supplied default constructor if not explicitly defaulted.
Next we see that there is a user-supplied copy constructor and copy assignment operator. Why? Well, with the data members nearby, it is easy to speculate that perhaps a deep-copy of the unique_ptr ptr_ is needed. We can't know that for sure of course without inspecting the definition of the copy members. But even without having those definitions handy, we are already pretty well informed.
With user-declared copy members, move members would be implicitly not declared if we did nothing. But here we easily see (because everything is predictably grouped and ordered at the top of the MyClass declaration) that we have explicitly defaulted move members. And again, because the data members are nearby, we can immediately see what these compiler-supplied move members will do.
In summary, we don't yet have a clue exactly what MyClass does and what role it will play in this program. However even lacking that knowledge, we already know a great deal about MyClass.
We know MyClass:
Holds a uniquely owning pointer to some (probably polymorphic) OtherClass.
Holds a string serving as a name.
Holds a bunch of doubles severing as some kind of data.
Will properly destruct itself without leaking anything.
Will default construct itself with a null ptr_, empty name_ and data_.
Will copy itself, not positive exactly how, but there is a likely algorithm we can easily check elsewhere.
Will efficiently (and correctly) move itself by moving each of the three data members.
That's a lot to know within 10 or so lines of code. And we didn't have to go hunting through hundreds of lines of code that I'm sure are needed for a proper implementation of MyClass to learn all this: because it was all at the top and in a predictable order.
One might want to tweak this recipe say to place nested types prior to the data members so that the data members can be declared in terms of the nested types. However the spirit of this recommendation is to declare the private data members, and special members, both as close to the top as practical, and as close to each other as practical. This runs contrary to advice given in the past (probably even by myself), that private data members are an implementation detail, not important enough to be at the top of the class declaration.
But in hindsight (hindsight is always 20/20), private data members, even though being inaccessible to distant code (which is a good thing) do dictate and describe the fundamental behaviors of a type when any of its special members are compiler-supplied.
And knowing what the special members of a class do, is one of the most important aspects of understanding any type.
Is it destructible?
Is it default constructible?
Is it copyable?
Is it movable?
Does it have value semantics or reference semantics?
Every type has answers to these questions, and it is best to get these questions & answers out of the way ASAP. Then you can more easily concentrate on what makes this type different from every other type.
Also, using =default instead of a hand-rolled one keeps the POD nature of the class, as it is described here in detail: Default constructors and POD
You often see = default when you are trying to maintain the rule of 5 to ensure the special member functions behave as you intend them to, and so that the reader of the class can see that you did consider how you wanted that function to behave.
You can use = delete if you intent to make something non-copyable or non-movable, for example. Though I have also seen people delete an inherited function if they do not want that specific derived class to have that function, though I'm not a huge fan of that since it tends to point towards poor architecture/design.
Related
So I have been reading about the Rule of Zero.
Simplified version: I do not understand the purpose of this rule. The rule of three and five are sort of "rule of thumbs", but I cannot see the "rule of thumb" or any other specific intentions with this rule.
Detailed version:
Let me quote:
Classes that have custom destructors, copy/move constructors or
copy/move assignment operators should deal exclusively with ownership.
Other classes should not have custom destructors, copy/move
constructors or copy/move assignment operators.
What does this mean? What do they mean by ownership, ownership of what?
They have also showed an example code(I guess it is connected to the introduction):
class rule_of_zero
{
std::string cppstring;
public:
rule_of_zero(const std::string& arg) : cppstring(arg) {}
};
What do they want to show with this, I am really lost on this one.
Also, they are also talking about the scenario when you are dealing with a polymorphic class and the destructor is being declared public and virtual and the fact that this block implicit moves. Therefore, you have to declare them all as defaulted:
class base_of_five_defaults
{
public:
base_of_five_defaults(const base_of_five_defaults&) = default;
base_of_five_defaults(base_of_five_defaults&&) = default;
base_of_five_defaults& operator=(const base_of_five_defaults&) = default;
base_of_five_defaults& operator=(base_of_five_defaults&&) = default;
virtual ~base_of_five_defaults() = default;
};
Does this mean that whenever you have a base class with a destructor that is declared both public and virtual, you really have to declare all the other special member function as defaulted? If so, I do not see why.
I know that this is a lot of confusion in one place.
The Rule of Zero
The rule of zero is another rule of thumb about how to write classes that need to use some resources like memory or other objects. In the example the dynamically allocated memory containing the characters of the string is a resource that has to be managed.
The recommendation is to let specialized classes manage resources, and do only that. In the example, std::string takes care of all the details of managing the allocated memory.
The rule emerged after the introduction of C++11, because the language and the standard library had improved, providing much better facilities to manage dynamically allocated object lifetimes (unique_ptr and shared_ptr). Also the containers now allow in-place construction, removing another reason for dynamic allocation. It should probably be seen as an update to the much older rule of three.
So if you previously would have used new in your constructor to create some member and delete in the destructor, you should now use a unique_ptr to manage the lifetime of the member, getting move construction and move assignment "for free".
Shared pointers can remember the correct destructor to call, so the common need for a virtual destructor goes away for objects that are exclusively managed via shared pointer, even if they are used polymorphically.
So basically a class that can rely on its members to do all the required actions for initialization, moving, copying and destruction should not declare any of the special member functions.
The Rule of Five
As always with C++ things are not always that simple.
As Scott Meyers pointed out, if you do have to add a destructor for whatever reason, the implicit generation of move constructors and move assignment operator are disabled, even if the compiler could generate them.
Then the compiler will happily copy your class all over the place instead of moving it which may not be what you expect. This may for example slow down your program, as more copying has to be performed. The compiler will not warn about this by default.
Therefore he recommends to explicitly specify which of the five special methods you want, in order to avoid surprises due to unrelated changes. He still recommends writing non-resource-management classes such that the defaults generated by the compiler can be used.
For example, I want to declare a class but I want the client to not be able to use the copy constructor (or copy assignment operator)
Both of the following two does not allow the use of the copy constructor:
1.
class Track
{
public:
Track(){};
~Track(){};
private:
Track(const Track&){};
};
2.
class Track
{
public:
Track(){};
~Track(){};
Track(const Track&)=delete;
};
Is one of these ways "more correct" than the other or are equal? Is there any side-effect?
//Does not compile with both the above ways
int main()
{
Track l;
Track p(l);
}
Making it private is the "old" way of doing it. The constructor still exists, but it is private, and can only be invoked from within another class member function.
= delete deletes the constructor. It is not generated by the compiler, and it simply will not exist.
So most likely, = delete is what you want. (although with the caveat that not all compilers support this syntax yet, so if portability is a concern...)
Declaring a copy constructor private still allows member functions of the Track class to copy-construct instances of that class, while making it deleted simply forbids copy-constructing that object.
In C++11, deleting a copy constructor is the right way to express the fact that a class is non-copyable (unless of course it makes sense for you to let member functions of Track, or friends of Track, to copy-construct Track objects).
Making a constructor private was basically a "hack" in the old C++, since it was the only way to prevent users from using them. The ability to delete special member functions was only introduced in C++11, and it's the better and more idiomatic way to say that a class cannot be copied. since it is explicit about the intention.
Private constructors have other uses other than forbidding their use entirely (e.g. they may be called by static class member functions). So just making a constructor private doesn't communicate the intention very well, and the resulting error is not very clear, either.
Your first solution conveys to the reader that the copy-constructor is private and is not to be used.
Your second solution is only valid in C++11. Because of this, I'd say the more portable and readable implementation would be your first, using the private-property.
In the first case, you are essentially declaring a private copy constructor and then not providing any implementation. By declaring them private, non-members cannot copy it.
In the second case, the syntax forbids a copy being made. This is C++ native.
The major difference as a programmer is readability and understanding the code. The first case is redundant, why declare the copy constructor, make it private, and not implement it. The client has to infer a lot here.
You can just use "= delete" and clearly imply what you're trying to do.
Your first approach doesn't prevent the class itself from copying itself. The traditional way to solve this is to declare the copy-constructor private and to leave it unimplemented.
An issue with that, however, is that the intent might not be obvious. Someone reading the code might not understand why an orphaned declaration exists and might mistakenly remove it. Comments can help, as would privately inheriting from boost::noncopyable if Boost is available to you.
The second approach makes the intent obvious and is what you should prefer if you can use C++11.
If you are on C++11, use delete. The reason is that it makes the call explicit and the intent clear. You could still accidentally use a private constructor (e.g. in a restricted set of scopes), but the compiler will forbid you from ever using a deleted constructor.
One issue of the private constructor is that the class and friends can still use it -- this results not in access errors but link errors, which can be hard to trace back to the callsite.
If your necessary toolchains do not support deleted constructors (= delete), you should not define it (as seen in your question) -- only declare it and leave it undefined, e.g.: private: \n Track(const Track&);
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Why copy constructor and assignment operator are disallowed?
I'm learning C++ from a solid C background, and in the eagerness to avoid the errors of previous C++ that I gleaned from reddit and hacker news, I've been using the Google C++ style guide and LLVM's source code as references for my own code. One thing that sticks out is both the projects' use of the following code. The following is taken from LLVM's include/Support/MemoryBuffer.h:
MemoryBuffer(const MemoryBuffer &); // DO NOT IMPLEMENT
MemoryBuffer &operator=(const MemoryBuffer &); // DO NOT IMPLEMENT
Google echoes this usage. Clearly, it's a good thing to disable these "copy constructors".
So my question is: why are these things so scary, and (if they are not guarded against) what does their use look like and what effect does it cause in code?
When an object has to manage its own resources, such as memory or a system handle, then the default copy constructor and assignment operator are no longer appropriate. That means you have to override them.
However, sometimes it doesn't make any sense to copy such an object. Or, said differently, some objects are not meant to be copied. Sometimes it's not even possible to write such a constructor or assignment operator. In that case, it's best to disable copy and assignment to make sure they're not copied by accident.
The standard's iostream are a good example.
All in all, it's a, say, special case. Definitely not something you would encounter often.
There is nothing scary about copy-constructors and they should not be viewed as such.
However, that said, there are times where copying an object simply doesn't make sense. In the example you provided, a memory buffer is a good example of something that makes no sense to copy. It has perhaps been used to store the data of allocated objects. What does a copy provide? A duplicate of the raw data of all those objects and not much else (the objects can't use it to de-allocate with, for example).
So, once we have decided that it makes no sense to copy our class, it also makes sense that we should prevent the programmer from doing it. The compiler will be sneaky and make default copy constructors and assignment operators for us, if we don't declare them ourselves. So, if we DO declare them (we don't need to provide an implementation) and make sure those declarations are private, then the compiler will issue a compile-error if the programmer attempts to do just that.
In C++03, declaring a copy constructor and assignment operator with no definition as private is a way to prevent people from being able to copy instances of your class. If anyone attempts to do so, they'll get a compile error complaining that the assignment operator and copy constructor are private. Additionally by providing no definition if the class's own methods try to use the functions they will get a linker error complaining the operator and copy constructor are not defined. This is necessary because otherwise the compiler will generate a copy constructor and assignment operator for you, which often will not do what you want (a shallow copy).
In the new C++11 standard, there is a better way to do this. The delete keyword can be used in declarations like so:
struct NoCopy
{
NoCopy & operator =( const NoCopy & ) = delete;
NoCopy ( const NoCopy & ) = delete;
};
NoCopy a;
NoCopy b(a); //compilation error, copy ctor is deleted
Example taken from here.
Sometimes, making copies do not make sense (eg. a std::unique_ptr, a mutex object, or a database connection object, etc). Or making copies is inefficient, and you want to prevent this operation. Or implementing the copy constructor correctly is painful and fragile, and you'd prefer not to rely on its presence. Deleting the copy semantics is done by declaring the copy constructor private.
Another popular option is to inherit from boost::non_copyable.
The C++11 standard offers an alternative to the ubiquitous use of the copy constructor. This goes by the name of move semantics, and allows you to move objects instead of copying them. Move semantics pretty much always make sense: returning an object from a function moves it for instance. You can also explicitly move an object into some function taking its argument by value.
Note that C++11 in principle allows you to delete copy semantics in this way:
struct foo
{
foo(const foo&) = delete;
void operator=(const foo&) = delete;
};
instead of making them private, like in C++03.
Whenever I would have had to declare and implement a copy constructor, I nowadays find myself almost always disabling the copy semantics. With some habit, it makes sense: if copy semantics are not trivial, there is a chance that something is wrong with copying. One notable exception is reference counting though (see the class template std::shared_ptr).
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.
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.