Probably all that I'm asking for is a link to a website that I have yet to find. But coming from a Java background, what are the general guidelines for handling memory allocation and deletion in C++? I feel like I may be adding all sorts of memory leaks to my application. I realize that there are several variants of smart pointers, and you can mention them too me as well, but I'd like to focus on standard C++ pointers.
Usually, we use new
to allocate memory, and delete
to free it. (Mainly because new
calls the appropriate constructors, and delete
the appropriate destructors).
But most of people here will advise you against using raw pointers other than for educational purposes (well except when the overhead of smart pointers is significant, like in embedded programming).
Knowing of things work is important, but in most cases, you can take advantage of well designed smart pointers classes to make things easier for you (and often safer).
Smart pointers exist for a reason: to help programmers do great programs without having to care too much about handling allocation/deallocation.
Use pointers with extreme paranoia. For every member variable that you declare in a class, document whether it owns the memory lifetime of the memory it points to. If it does, then it's responsible for allocating and freeing the memory. And if it does own the memory it points to, document it CLEARLY! Also remember, allocate in the constructor and deallocate in the destructor. It's a great rule, that you ignore at your peril. Also NULL out your pointers except when you are using them. NULL them when they are initialized, and after you free them. Put lots of asserts everywhere checking the integrity of your pointers BEFORE you dereference them. Put in real guards to handle situations when they are bad.
Last and most important of all:
FIRE any bozo in your company who abuses these policies!!! They are literally injecting untold damage into your product, and causing lots of bugs and headaches down the road.
My usual policy is this
- Use smart pointers where usage is at all complex.
- All raw pointers are owned by a specific object that is responsible for deleting it.
- The constructor always either allocates the pointer or initializes it to null if it's to be set later.
- The destructor always deletes any contained pointers
- Those rules ensure that pointers get deleted when their owning objects are deleted eliminating most common memory leak situations.
- Never pass an internal pointer into another object, always pass the container object and have the the called function call member functions of the container object to act on the "pointer".
- Disable copying of the container object. In rare cases implement the copy so that it copies the pointed to object. But never allow the owning object to be copied without also copying the contained object.
- The previous two rules ensure that you can't have copies of the pointer pointing to deleted memory.
- Don't try to implement reference counting. If you need a reference counted pointer use a smart pointer class and contain that.
I've found those rules generally ensure you can use raw pointers safely and efficiently, and if you want to break those rules then use a smart pointer instead.
I also came from Java and it took a while to learn how good design looks like in C++. At first, it's hard to think about who's responsibility it is to delete things. The answer is to defer these responsibilities to objects, to let objects own/manage other objects or resources and let them worry about deletion/release or copying. C++ makes this easy via constructors, destructors, etc. They keyword is "RAII" (resource acquisition is initialization).
Often, I manage to organize the "x owns y"-relationship as a forest where the tree's roots all live on the stack (automatic memory). By using standard containers and avoiding pointers as data members I reduce the number of new/delete calls in my code to a minimum (almost none). This is the simplest thing to work with. Sometimes, you may feel the need to use shared-ownership smart pointers, but in my experience, people tend to overuse those. But they are, of course, useful in some cases.
If you really do need to handle raw pointers, then I suggest wrapping them with smart pointers if possible. If you will be storing them in an STL container, you'll need to use a tr1::shared_ptr
instead of an auto_ptr
.
While you're learning I would suggest steering clear of pointers whenever you can, to avoid headaches. For example, if you want an array of int
s, you can use a vector
rather than allocating and freeing the memory yourself. If you want to instantiate a class, do it in automatic memory, i.e.
MyClass myObject;
instead of
MyClass *myObject = new MyClass();
// ...
delete myObject;
Have you thought of using a garbage collector. This Garbage Collector is currently used by the Mono project, although I understand it's getting replaced with a more aggressive version. It may help, as its will provide a similar experience when developing in C/C++ as when you developed on Java.
I use following policy:
Never use raw pointers that own objects.
Foo *f=new Foo(); // Bad!
Even in Classes :
class Bar { Bar(Bar const &); // non copyable void operator=(Bar const &); public: Bar() { f1_=new Foo(); f2_=new Foo(); // this throws then f1_ never destroyed! } ~Bar() { delete f1_; delete f2_ ;} Foo *f1_,*f2_; }; // Bad code
Correct:
class Bar { Bar(Bar const &); // non copyable void operator=(Bar const &); public: Bar() { f1_.reset(new Foo()) f2_.reset(new Foo()); } std::auto_ptr<Foo> f1_,f2_; }; // Good code
For object without shared ownership use
auto_ptr
std::auto_ptr<Foo> f(new Foo()); // Good
For shared ownership or containers, use
boost::shared_ptr
orstd::tr1::shared_ptr
std::vector<boost::shared_ptr<Foo> > foos;
When I need to transfer ownership on object to some other object, use
auto_ptr
void assign_foo(std::auto_ptr<Foo> f) { /// I own foo } std::auto_ptr<Foo> transfer_foo(std::auto_ptr<Foo> f) { ... } // Now foo is owned by caller
So it is clear who gives whom a pointer.
Raw pointers are allowed only as references that can be null and they never own objects
void bar1(Foo *f) { do something with f if f!=NULL}
As others have said you need read up on RAII. I found this useful when I was learning C++, its old but gives the basic ideas.