I have a class with about 50 members. 1 of them is a pointer. So, naturally I have to make my own copy constructor, copy everything and create a new instance of that object. My question is: Is there a shortcut or some special way I can have everything copied (like the default copy constructor does) then just handle that one pointer? Rather than manually copying each member.
I'd wrap your pointer into a helper class that does the copy in the way you like. That way you can leave the big class with the default copy ctor.
Use a smart pointer instead, then rely on your class' default copy constructor.
Standard smart pointers (unique_ptr, shared_ptr) don't have copy constructors that would copy their objects, but you can roll up your own.
Since you say that the default copy won't work I'll assume that your object owns the pointee.
If all you need is a shallow copy that cleans up properly, use shared_ptr from C++11 or boost.
If you need a deep copy, I would first suggest to store the contained object by values instead of by pointer. Then you get the copy for free and you don't have to worry about one extra set of memory management.
Finally if none of those are an option I'd write a pointer wrapper that handles deep copy semantics (I don't believe boost offers such a class).
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).
Been using boost's disjoint_set. It has a copy constructor. To my understanding, it uses pointers that are handed over during the constructor call to access it's data and it doesn't manage memory allocation on its own. Therefore, when you make a copy, the actual data (unlike when you copy a std::vector<T>), isn't copied. You get two seemingly separate instances (cause you aren't using a reference) that access and modify the same data. This seems haphazard and the use case is not clear.
So the question is, why would you say that disjoint_set's copy constructor is useful and why would you make a copy constructor that returns a shallow copy of an instance?
you mean this one: inline disjoint_sets(const self& c) : rank(c.rank), parent(c.parent) {}? Its not clear here whether its shallow or deep copy. rank and parent are of template types : class RankPA, class ParentPA, so its up to the client of this template whether copy should be shallow or deep.
why would you make a copy constructor that returns a shallow copy of an instance?
its dangerous when you have dynamically allocated memory, instead you might consider using move semantics.
To my knowledge, in theory, if a class has a raw pointer member, then the default copy constructor will do a shallow copy of that pointer, such that when the original object is destroyed, the pointer member in the copy will have had the value to which it pointed deleted. This seems to imply that outside of the case where we want to restrict copying for some reason, any class with a raw pointer member should define a copy constructor to do a deep copy on that pointer.
I am working with a respectable third party API, and I've come across a class with a raw pointer member, but no defined copy constructor, which casts doubt on my understanding above. Am I missing something?
UPDATE: The third party informed me that this class is not meant to be copied, as the object represents a visual element. They noted that they should have made a private copy constructor.
I think std::reference_wrapper is part of a respectable API (the C++ standard library). It has a copy constructor but that's not necessarily explicitly defined in the implementation code, because it just copies the raw pointer. So there you are: having a pointer member doesn't always imply ownership.
As a counter-example, an example of where you have non-owning pointer member but still need to take charge of copying, an object can contain a pointer to a part of itself. It would be ungood if copying such an object resulted in its internal pointer pointing to a part of some other object.
In summary, it depends. Must often you need a defined copy constructor. But absolutely not always.
For C++03 the law of three (or "rule of three") was a rule of thumb that if you needed either a destructor, a copy assignment operator or a copy constructor, then you probably needed all three.
So check if there is a copy assignment operator or destructor. In that case a copy constructor is probably required, and missing.
In C++11 and later some people extend it to the law of five, by including move assignment operator and move constructor, and some people reduce to the law of zero, by requiring that all ownership should be expressed via smart pointers or collection objects.
In an ideal world, any raw pointer member could be assumed to be a non-owning pointer. Since, if you had wanted an owning pointer you would have used a smart pointer!
A non-owning pointer member will point at an object whose lifetime is managed outside of the class and should be (by design) longer than the lifetime of the pointer.
The default behaviour when you copy the class is for the copy to also point at the same object. Often that is the behaviour you want. If not, yes, you will have to change that behavior.
Of course, we don't live in an ideal world and there are many places where owning raw pointer members are used. In that case, you are right, the default copy constructor is not appropriate (see Alf's answer regarding the rule of 3/5).
No, you're not missing anything. In general.
I'm hesitant to make any specific guarantees without knowing what library you're talking about and what the semantics of that class are (documented or otherwise) but, on the surface of it, this sounds like a library bug.
It's possible that the class doesn't own the pointee. This will likely be the case if its constructor doesn't allocate it, and its destructor doesn't de-allocate it.
Barring that, though, you're right.
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.
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?