Say I have a struct "s" with an int pointer member variable "i". I allocate memory on the heap for i in the default constructor of s. Later in some other part of the code I pass an instance of s by value to some function. Am I doing a shallow copy here? Assume I didn't implement any copy constructors or assignment operators or anything for s... just the default constructor.
The problem with the shallow copy is that the two objects are not independent. If you modify the one object, the change will be reflected in the other object. A deep copy is a fully independent copy of an object. If we copied our object, we would copy the entire object structure.
Shallow Copy stores the copy of the original object and points the references to the objects. Deep copy stores the copy of the original object and recursively copies the objects as well. Shallow copy is faster. Deep copy is comparatively slower.
Shallow copies are useful when you want to make copies of classes that share one large underlying data structure or set of data.
A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original. A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.
To follow up on what @[don.neufeld.myopenid.com] said, it is not only a shallow copy, but it is either (take your pick) a memory leak or a dangling pointer.
// memory leak (note that the pointer is never deleted)
class A
{
B *_b;
public:
A()
: _b(new B)
{
}
};
// dangling ptr (who deletes the instance?)
class A
{
B *_b;
public:
A()
... (same as above)
~A()
{
delete _b;
}
};
To resolve this, there are several methods.
Always implement a copy constructor and operator= in classes that use raw memory pointers.
class A
{
B *_b;
public:
A()
... (same as above)
~A()
...
A(const A &rhs)
: _b(new B(rhs._b))
{
}
A &operator=(const A &rhs)
{
B *b=new B(rhs._b);
delete _b;
_b=b;
return *this;
};
Needless to say, this is a major pain and there are quite a few subtleties to get right. I'm not even totally sure I did it right here and I've done it a few times. Don't forget you have to copy all of the members - if you add some new ones later on, don't forget to add them in too!
Make the copy constructor and operator= private in your class. This is the "lock the door" solution. It is simple and effective, but sometimes over-protective.
class A : public boost::noncopyable
{
...
};
Never use raw pointers. This is simple and effective. There are lots of options here:
Example:
// uses shared_ptr - note that you don't need a copy constructor or op= -
// shared_ptr uses reference counting so the _b instance is shared and only
// deleted when the last reference is gone - admire the simplicity!
// it is almost exactly the same as the "memory leak" version, but there is no leak
class A
{
boost::shared_ptr<B> _b;
public:
A()
: _b(new B)
{
}
};
Yes, that's a shallow copy. You now have two copies of s (one in the caller, one on the stack as a parameter), each which contain a pointer to that same block of memory.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With