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.
3 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) { } };