views:

318

answers:

9

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.

+5  A: 

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.

ereOn
LOL. Funniest thing I've read all day!!
C Johnson
@C Johnson: Glad I made you laugh :) Care to elaborate what you think is that funny ?! :)
ereOn
ereOn; smart pointers or not, you might want to add a note regarding custom allocators and memory pools.
roe
Hey, you edited out the educational part? You should put it back in. :) Edit: Oh I see it is there now. Cool!
C Johnson
@C Johnson: I never edited it out. Perhaps you should buy glasses... and a book about smart pointers :) Or just tell us clearly why you seem to disagree. I don't bite, I swear.
ereOn
+5  A: 

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.

Edit: link Favorite c++ website

C Johnson
Or you can use smart pointers when the overhead is acceptable, to avoid having to explicitly set to `NULL` :)
ereOn
We are starting to use smart pointers more nowadays. But we still have 99,567 more to go! ;)
C Johnson
+14  A: 

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.

John Burton
Nice policy. Here is my +1.
ereOn
Sometimes, you don't need to do anything special with pointers as members. Think of iterators. So, it really depends on what semantics you are going for. Deleting objects in the iterators' destructors is a bad idea. ;-)
sellibitze
There are always exceptions to a rule :) I would argue that even in this case you are taking a calculated risk though. If your object stores a pointer to an object then that object can be deleted without it's knowledge which is a bad thing. That risk is probably acceptable for a common idiom like an iterator that has usage patterns that don't lead to a huge risk of misuse. But for a general case I would suggest that you need to think twice about storing a raw pointer to an object you don't control the lifetime of.
John Burton
Not suggesting that you don't do it, sometimes it's necessary... But when I do it, it's a deliberate choice to break my policy and a good indicator that there maybe lifetime issues with that object.
John Burton
+4  A: 

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.

sellibitze
+1, well said, completely agree.
roe
+1  A: 

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 ints, 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;
robinjam
`shared_ptr<>` is not always required. Sometimes a `scoped_ptr<>` is enough and has a less overhead.
ereOn
`MyClass myObject();` declares a function, not a variable.
sellibitze
@ereOn: I always thought that STL containers always required their contained objects to be copyable. Thanks for the heads-up.
robinjam
@sellibitze: Sorry, typo :(
robinjam
@robinjam: Sorry, my comment was unclear. I wasn't explicitely talking about containers, but about pointers in general. My mistake. I believe STL containers indeed require the contained objects to be copiable. However, note that `boost` also provides specific containers, similar to the STL ones, but that are easier to use with smart pointers.
ereOn
+4  A: 

Pair every new (or new[]) with a delete (or delete[]).

RAII is your friend. Develop classes that acquire resources in the constructor and release them in the destructor.

trhoades
A: 

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.

scope_creep
+1  A: 

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 or std::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}
    
Artyom
A: 

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.

Lewis Jubb