Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Question about shallow copy in C++

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.

like image 511
MrDatabase Avatar asked Oct 19 '08 07:10

MrDatabase


People also ask

What are problems with shallow copy?

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.

Why are shallow copies faster?

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.

Why would you want a shallow copy?

Shallow copies are useful when you want to make copies of classes that share one large underlying data structure or set of data.

Does shallow copy create a new object?

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.


2 Answers

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:

  • Use string classes instead of raw char pointers
  • Use std::auto_ptr, boost::shared_ptr, boost::scoped_ptr etc

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)
  {
  }
};
like image 67
1800 INFORMATION Avatar answered Oct 18 '22 22:10

1800 INFORMATION


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.

like image 28
Don Neufeld Avatar answered Oct 18 '22 21:10

Don Neufeld