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.
Related
Why C++ provide a copy constructor? The assignment operator can do the same task. Is there any advantage of copy constructor over assignment operator?
Stuff you can do with a copy constructor that you can't do (either easily or at all) with the assignment operator:
Copy classes that don't have a default constructor. For example, if a class represents an open file, you might not be able to construct one without passing it a file name to open.
Copy classes that have an expensive default constructor. Maybe the constructor allocates a lot of memory, which will then be released as soon as you use the assignment operator to copy a new state into the object.
Pass an instance of the class by value. This is kind of the original purpose of the copy constructor. In C, if you pass a struct by value, the compiler just does a bitwise copy of the struct so the receiving function has a local copy that it can modify without affecting the caller. But C++ recognizes that a bitwise copy is not the best way to copy most objects, so it lets you write your own copy constructor (and the default copy behavior is different too, since class members may have custom copy constructors).
Copy a class that contains references, because you can't reassign a reference after the class has already been constructed. The copy constructor and assignment operator just do different things where references are concerned. The copy constructor initializes the reference to point to the same object that the reference points to in the instance that is being copied; the assignment operator actually copies the value of the referenced object.
Copy a class with const members. (Note that a class can have a default constructor but still have const members.)
With or without a copy constructor, you still have to initialize a new object to a stable initial state, which the assignment operator can then update later.
While you can certainly do that without a copy constructor, having a copy constructor helps to optimize a new object's initialization, by setting it to copy another object's state up front, without requiring you to first initialize the new object to a default state and then have a separate assignment reset that state afterwards. This way, you can set the new object's state in 1 operation instead of 2 operations.
Yes, the two are different. You can't always just implement your copy constructor as
Foo(const Foo& f) {
*this = f;
}
The assignment operator assumes that you have a valid, fully constructed object. The copy constructor makes no such assumptions. This means that, depending on your class, the assignment operator may try to clear whatever data is on the object before re-initializing. Or may even repurpose the data already on the object.
Take this example.
Jack and John are twins.
You could say this is Jack and that is Jack.
But although John is the spitting image of Jack, he ain't no Jack.
When you use the assignment operator you can refer to the exact object in memory (returning *this) or provide some custom behavior.
When you use the copy constructor you want to create another object in memory that has a copy of the properties of the original object, but that can evolve in a different direction.
If you want a deeper answer I think this blog post is better.
Assignment is a little more tricky than initialization, because what
we are essentially doing is destructing the existing object and then
re-constructing it with new values. In a more complex class, you might
need to free various resources and then re-allocate them using copies
of the resources from the object being copied. std::unique_ptr makes
our life easy here, because assigning a new instance of
std::unique_ptr to an existing std::unique_ptr object with = as above
(or by using reset()) first frees the old pointer, so releasing the
resource is handled for us automatically (this is the same reason our
class doesn’t need a destructor – when std::unique_ptr goes out of
scope as our object goes out of scope, std::unique_ptr‘s destructor is
called and the resource is freed automatically).
I'm trying to figure out when to use move semantics and when to use a copy constructor and assignment operator as a rule of thumb. The type of pointer you use (if any) in your class seems to be affected by this answer, so I have included this.
No pointers - Based on this answer, if you have a POD class with primitive types like int and string, you don't need to write custom move or copy constructors and operators.
unique-ptr - Based on this answer, when using move semantics, then unique_ptr is a better fit over shared_ptr as there can only be one unique_ptr to the resource.
shared_ptr - Equally, if using copy semantics, shared_ptr seems the way to go. There can be multiple copies of the object, so having a shared pointer to the resource makes sense to me. However, unique_ptr is generally preferred to shared_ptr so avoid this option if you can.
But:
When should I use move semantics?
When should I use copy semantics?
Should I ever use both?
Should I ever use none and rely on the default copy constructor and assignment operator?
As the name indicates, use unique_ptr when there must exist exactly one owner to a resource. The copy constructor of unique_ptr is disabled, which means it is impossible for two instances of it to exist. However, it is movable... Which is fine, since that allows transfer of ownership.
Also as the name indicates, shared_ptr represents shared ownership of a resource. However, there is also another difference between the two smart pointers: The Deleter of a unique_ptr is part of its type signature, but it is not part of the type signature of shared_ptr. That is because shared_ptr uses "type erasure" to "erase the type" of the deleter. Also note that shared_ptr can also be moved to transfer ownership (like unique_ptr.)
When should I use move semantics?
Although shared_ptr can be copied, you may want to move them anyways when you are making a transfer of ownership (as opposed to creating a new reference). You're obligated to use move semantics for unique_ptr, since ownership must be unique.
When should I use copy semantics?
In the case of smart pointers, you should use copying to increase the reference count of shared_ptrs. (If you're unfamiliar with the concept of a reference count, research reference counted garbage collection.)
Should I ever use both?
Yes. As mentioned above, shared_ptr can be both copied and moved. Copying denotes incrementing the reference count, while moving only indicates a transfer of ownership (the reference count stays the same.)
Should I ever use none and rely on the default copy constructor and assignment operator?
When you want to make a member-by-member copy of an object.
When should I use move semantics?
I presume by this you mean, "When should I give my class a move constructor?" The answer is whenever moving objects of this type is useful and the default move constructor doesn't do the job correctly. Moving is useful when there is some benefit to transferring resources from one object to another. For example, moving is useful to std::string because it allows objects to be copied from temporaries without having to reallocate and copy their internal resources and instead by simply moving the resource from one to the other. Many types would benefit from this. On the other hand, moving is useful to std::unique_ptr because it is the only way to pass a std::unique_ptr around by value without violating its "unique ownership".
When should I use copy semantics?
Again, I presume by this you mean, "When should I give my class a copy constructor?" Whenever you need to be able to make copies of an object, where internal resources are copied between them, and the default copy constructor doesn't do the job correctly. Copying is useful for almost any type, except those like std::unique_ptr that must enforce unique ownership over an internal resource.
Should I ever use both?
Your classes should provide both copy and move semantics most of the time. The most common classes should be both copyable and moveable. Being copyable provides the standard semantics of passing around an object by value. Being moveable allows the optimisation that can be gained when passing around a temporary object by value. Whether this means having to provide a copy or move constructor depends on whether the default constructors do the appropriate things.
Should I ever use none and rely on the default copy constructor and assignment operator?
The default copy and move constructors just do a copy or move of each member of the class respectively. If this behaviour is appropriate for copying and moving your class, that's great. Most of the time, this should be good enough. For example, if I have a class that contains a std::string, the default copy constructor will copy the string over, and the default move constructor will move the string's resources to the new object - both do the appropriate job. If your class contains a std::unique_ptr, copying will simply not work, and your class will only be moveable. That may be what you want, or you may want to implement a copy constructor that performs a deep copy of the resource. The most important case in which you should implement copy/move constructors is when your class performs resource management itself (using new and delete, for example). If that's the case, the default constructors will almost never be doing a good job of managing those resources.
Everything here applies similarly to the assignment operator.
Node*Clone(){
numClones++;
Node*cloned=new Node(*this);
return cloned;
}
I have a default constructor (taking no arguments) and I have no declared copy constructors, so I'd expect this to simply copy the entire contents of the memory of *this and return a pointer to it.
However, I am getting error on the new line above:
Call to implicitly deleted copy constructor
Two possible issues but I don't think they should affect this:
this has a unique_ptr attached to it. That is it contains a container of unique_ptr and is itself stored in another container of unique_ptr. But I am not moving that pointer, I am creating new object not attached to the prior object, right?
this is actually a subclass of Node but I want to return a pointer to a base class
As Jeffrey said, std::unique_ptr cannot be copy-constructed.
Also your Clone methods is not logically correct. Because you are instantiating a Node object there - a base class. So it will not be a copy actually
As a solution you may declare a Clone method in the base class and make in pure virtual:
class Node
{
virtual Node * Clone() const = 0;
}
And make your subclasses implement it
PS: don't forget about virtual or protected dtor in the interface
The error message "Call to implicitly deleted copy constructor" means that your class, one of its base classes and/or some of the data members of that class or any of its base classes are declared as non-copyable (or are treated as non-copyable by the compiler which may happen, for example, when at least one of data members is a reference). Therefore, compiler cannot come up with a "default" copy constructor that you are attempting to call with new Node(*this);
The proper way in such a case is to actually find what objects exactly are non-copyable and either make them copyable so that compiler could create an implicitly defined copy constructor, or implement your very own "copying logic" and not use a copy constructor.
Another alternative is to use some sort of a "smart" pointer pointer (i.e. std::shared_ptr). But in that case you get a shallow copy instead of a deep copy.
Since you are doing a copy of yourself, I would really suggest you implement a copy constructor. It's best practice to control, plus if you add memory points in the class, you will really mock things up..
Don't rely on this in your case, here is why not:
Conditions for automatic generation of default/copy/move ctor and copy/move assignment operator?
The problem is caused by your attempt to copy construct a std::unique_ptr (by copying a Node) which, by definition, does not have a copy constructor.
You probably meant to use std::shared_ptr.
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?
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.