Why would you want a shallow copy (instead of a reference)? - c++

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.

Related

What is the use of copy constructor while the same can be done with assignment operator '='?

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).

When to provide user-defined copy constructor and assignment operator?

Do we only need to write a copy constructor and assignment operator when we have pointer data members (because otherwise two pointers could point to the same object when the compiler-generated copy ctor does a shallow copy)?
If all our data members are allocated on the stack we can just rely on compiler-defined copy constructor and assignment operator?
Pointers are undoubtedly the most obvious case, but not really the only one.
Another example would be a class that opens a database connection in the ctor and closes it in the dtor. A copy ctor would need to do something to duplicate the database connection, so the copy's connection to the database is closed separately from the original's connection.
Use the compiler defined copy constructor if it works.
The shallow copy is typically faster, and even though they may cope the pointer address instead of the pointed data that can be what you want in some cases. For example you might want a pointer to the texture that you share with other parts of the code.
Only if you need a copy of the data you should fix the copy constructor.
A warning would be member variables that are classes with their own copy constructors, can't give you any promises on what happens then.
If a base class or an object contained by the class has no copy constructor (ie. a stream) then if you wish your class to be copy constructable then you must implement a copy constructor.
For the stream case, this copy constructor may have to
a) duplicate the file,
b) create a new empty file that can be written to,
c) or save the address of the stream so that both objects can write to it.
The last option is the most complicated and would probably require use of a shared_ptr.
Generally, I like to put all my resources into classes maintaining these resources and these tesource maintainer need a copy construct, copy assignment, and a destructor. Depending on the resource, the copy constructor and copy assignment may be deleted.
What is not as obvious is that some classes not maintaining resources directly may need a copy assignment: if you want your copy assignment to be strongly exception safe, you often need to implement the copy assignment. For example, assume your class stores two vectors. The generated copy assgnment does a memberwise assignment. Normally, memberwise assignment is fine. However, if the assgnment to the second vector throws an exception, it is impossible to restore the original state! A better copy assgnment would look like that:
T& T::operator= (T other) {
other. swap(*this);
return *this;
}
Since swap() can be implemented without throwing, This imolementation is strongly exception-safe.

Copy constructor shortcut

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).

Should we explicitly write a copy constructor if the class member is a vector?

struct myType {
vector<char*> ls;
};
Here ls is holding pointers to char. If a user-defined copy constructor for myType is not provided, will myType's default copy constructor do a deep copy of ls?
Here ls is holding pointer to char. If copy constructor is not provided, will default copy constructor do the deep copy?
The default copy constructor will copy all members – i.e. call their respective copy constructors.1 So yes, a std::vector (being nothing special as far as C++ is concerned) will be duly copied.
However, the memory pointed to by the char* elements inside the vector will of course not, since C++ doesn’t know and doesn’t care what the pointers point to.
But the solution here isn’t to provide a custom copy constructor. It’s to use a data structure instead of raw pointers (char*) which does. And this happens to be std::string (or std::vector<char> depending on the intent).
1 Thus creating a transitive closure of the copy operation – this is how deep copying is generally implemented, but of course an implementor of the copy operation can always break out of it.
will default copy constructor do the deep copy?
Of course not. The compiler cannot know who owns the pointed-to memory.
If deep copy is required, you have to implement the copy constructor and manually copy each char* into new memory for the vector in the copied-to object.
If you use the char* as zero-terminated strings, then you should really use std::string instead. If you do, the default constructor is enough.
No, it will not.
C++ will recursively call the copy ctor of all subobjects. So it will call the copy ctor of the vector, which will in turn call the copy ctor of the char* which will copy the char* by value. C++ will never automatically allocate memory and copy the data. It can't even possibly do that, since it does not know what the data is you are pointing at, and how much it should copy.
When you use strings, you should prefer using std::string, as this will do all the copying for you. If it is some binary data buffer that needs special handling, then you need to do that yourself in your copy ctor (and when you are done, think a moment about if it was really sensible to think about requiring C++ to do that for you).
When you write your own copy ctor, you always should mind the Rule of Three

What happens (exactly) if you leave out the copy-constructor in a C++ class?

What happens (exactly) if you leave out the copy-constructor in a C++ class?
Is the class just memcpy'd or copied member wise?
The class is copied member-wise.
This means the copy constructors of all members are called.
The default copy constructor is made mebmber wise.
The same member-wise approach is also used for creating an assignment operator; the assignment operator however is not created if the class has reference members (because it's impossible to rebind a reference after construction).
You get the default copy that copies the contents from one object into the other one. This has the important side effect that every member containing a pointer is now shared between the original object and the copy.
Notice that with a member-wise copy, if you have allocated any memory, your data structures will share that memory allocated - so it is important, if you want to create a deep (independent) copy of data to create a copy constructor for structures which allocate memory. If your structure is not allocating memory, it is less likely to really require a copy constructor.
However, if you implement the copy constructor, don't forget the Rule of Three: copy constructor, assignment operator, destructor. If one is implemented, all three must be implemented.
Regards,
Dennis M.