1

I am working in C++ with classes and nested classes. I do have a lot of classes and nested classes. I don't know when should i deallocate the memory. Is there a software that shows you where or when to deallocate a pointer from a class?

Can anyone help me? thx

I would like to mention that i am working in c++ under ubuntu. My files are a .cpp and a .h file. There is no main. I am using class *x= new class(). I didn't did delete x because I don;t know when should i delete it.

sunset
  • 1,359
  • 5
  • 22
  • 35
  • The question presupposes that there are choices, which is simply not the case: each means of allocating memory comes with one and only one correct way to deallocate it. Automatic variable go away when the scope ends; smart pointer manage themselves; placement `new` requires you to call the destructor manually; `new[]` assigned to a dumb pointer requires `delete[]`; `new` and `*` requires `delete`; and (heaven forbid!) `malloc`/`calloc` requires you to manage the `free`ing yourself. Perhaps sunset wants to know the advantages and disadvantages of each choice for *allocating* memory... – dmckee --- ex-moderator kitten Aug 23 '11 at 21:50

6 Answers6

4

The best way to deallocate memory is not to free it explicitly but use the automatic variables. (In C++ you don't have to allocate everything dynamically)

MyClass obj; // it gets deallocated automatically

In case, you have need of using dynamic memory allocation (with new()) then best way is to use smart pointers (which are again automatic objects and takes care of delete the memory pointed).

Otherwise you should deallocate it with delete p;, when you are sure that you are done with p.

iammilind
  • 68,093
  • 33
  • 169
  • 336
  • thx for your answer. Could you tell me what is the difference between MyClass obj and MyClass *obj = new MyClass();? when someone shoudl use the first form and when the second? thx!! – sunset Aug 23 '11 at 09:39
  • @sunset, You should always use the first form. Use 2nd form (`obj = new MyClass`), only when you are not sure that when you are done with `*obj`. If you know that when you are finished with `obj`; just use automatic variables (1st version) – iammilind Aug 23 '11 at 09:41
  • +1 for this simple answer. By the sound of it the OP was under the impression that you *always* have to say `new`. Advocating RAII and smart pointers would probably only be helpful after you're clear about the difference between automatic and dynamic storage. – Kerrek SB Aug 23 '11 at 09:48
  • @sunset: Regarding all your basic questions, why don't you spend some money on a good book? – Sebastian Mach Aug 29 '11 at 08:19
4

The lifetime of objects should be known to you who designs the software system, otherwise things will most likely go wrong sooner or later. That means you need to think how long a specific object is needed (who uses it). Together with this you need to know who owns the object. These two things will tell you how to create the object.

Knowing the lifetime of objects as well as their ownership will tell you if you need an object on the stack or on the heap. The former, automatic variables which you declare like this:

{
    ...
    SomeClass sc; 
    ...
} // sc will be destroyed here as it goes out of scope

is preferred if sc is only needed within that scope.

If you allocate objects on the heap with new you should have a reason to do so. E.g. they're shared in some what across other objects or an API requires you to pass a certain smart pointer.

SomeObject* so = new SomeObject;

Writing things like the above means you must handle the deallocation yourself and is NOT recommended! Use a smart-pointer instead so things can be cleaned up in a good way, like this:

{
    ...
    boost::scoped_ptr<SomeObject> so(new SomeObject);
    ...
} // boost::scoped_ptr will automatically handle deallocation here

If you change the above into a boost::shared_ptr,

{
    AnotherObject another;
    ...
    {
        ...
        boost::shared_ptr<SomeObject> so(new SomeObject);
        another.setObject(so); // sets so in another
        ...
    } // no deallocation of so here because another has a reference to it!!
} // when another goes out of scope (destroyed) so will be destroyed as well

one shared_ptr might go out of scope, but the object it holds is still alive as another object(s) has a reference to it. This can be very handy in cases where you have many using some resource and you want the resource to be available as long as the users are alive.

Put shortly, stay to automatic variables as much as you can and use smart pointers like boost::scoped_ptr and boost::shared_ptr when you need to.

murrekatt
  • 5,961
  • 5
  • 39
  • 63
4

To the OP: your comments indicate some confusion as to how C++ works. There are some important things you need to understand a few things:

  1. Dealing with pointers is inherently dangerous. Incorrectly using pointers may introduce Undefined Behaviour, which not only is an error in your program, but it's an error that may well not be detected by the compiler, not even giving you a wanring, and at runtime there is no telling how your program will behave: it may crash right there and then, but it may also continue running, but cause another part of the program, which is 100% correct, to either crash or just behave differently than it should. There is no automatic way to detect these situations with certainty, so good design is paramount.
  2. A pointer to an object is a different thing than the object it points to. As a side note, if you come from a language like Java, in C++ the term 'object' also refers to variables of built-in types, like int, double etc.
  3. A pointer to type X is a value type, that may or may not point to an object to type X. Apart from having a special value of 0 (NULL), it may simply point to a random place in memory which does not contain an object of type X. Such a pointer is called a 'dangling pointer'.
  4. The act of accessing an object pointed to by a pointer is called dereferencing the pointer. Dereferencing a dangling pointer or a null pointer is Undefined Behaviour. Furthermore, while it is possible for your program to check if a pointer is null, it's not possible to check if it's a dangling pointer. It is the programmer's responsibility to structure the program in such a way, that dangling pointers are never dereferenced.
  5. In one of your questions, you ask about creating a pointer. Creating a pointer definitely does not mean you have to call delete on it, because creating a pointer is different to creating an object to which the pointer would point. Consider the following piece of code, which creates a pointer: SomeType* pointer;
    While this does in fact create a pointer, it is a dangling pointer, and if you attempt to call delete on it, you will get Undefined Behaviour.
  6. The question of memory allocation is not to do with pointers as such, as with objects, for which memory is allocated or de-allocated. Typically, you do not allocate or de-allocate memory explicitly in C++, but instead create and destroy objects, and memory is allocated for them implicitly.
  7. The new operator does not create pointers, it creates dynamic objects, allocating the required memory for them, and returns a pointer to the newly created object. Dynamically allocated objects' lifetime will persist and they will keep occupying the memory that they occupy until you call delete on the pointer, which destroys the dynamic object (not the pointer itself) and deallocates the memory it occupies. If you repeatedly allocate dynamic object and fail to delete them after you stop using them, your memory gets filled up with unused objects: this is called a memory leak.
  8. Pointers may point not just to dynamically allocated objects, they may point to other kinds of objects as well: local variables, structure or class members, array elements. Just as there is no way of telling if a pointer is dangling, there is also no way to tell if it points to a dynamic object. Attempting to call delete on a valid pointer that points to anything else than a dynamic object results in Undefined Behaviour.
  9. There may be many pointers pointing at the same object. If the object is destroyed, either by calling delete in the case of dynamic object, or in any other way, all pointers, that pointed to it, become dangling pointers.
  10. Pointer variables or class/struct members are objects in their own right, but their lifetimes are not tied to whatever objects they point to: just as no pointed-to object is created when you create a pointer, the object pointed to (if any) is not destroyed when the pointer is destroyed. This makes it possible to safely destroy multiple pointers pointing to the same object, or to destroy dangling pointers.

An additional concern when creating dynamic objects with new and destroying them with delete is exception safety: in many cases code that looks at first like it would delete everything created with a new might not do so, because an exception is thrown. For example:

{
    SomeType *p = new Sometype
    // some code
    delete p;
}

In this case if 'some code' throws an exception, delete p is never reached and a memory leak occurs. Silimlarly:

class A {
    SomeType *p;
    // more members
public:
    A(): p(new SomeType()) /* more intializers */ { /* body */ }
    ~A() { delete p; }
};

In this case, if A constructor throws an exception after p is initialized, the destructor will never get called and you will have a memory leak.

Given these pitfalls, several design techniques exist to manage these problems.

Don't use pointers and/or dynamic objects unless necessary: In many cases, you can get by without dynamically allocating objects. In the case of local variables, where the variable's lifetime is limited to function scope you can just define the object as an automatic variable, so instead of:

{
    SomeType* p = new SomeType();
    // do something with *p
    delete p;
}

you do:

{
    SomeType var;
    // do something with var
} // var destroyed here

In the second case, var will be destroyed and it's memory will be deallocated when it goes out of scope - even if an exception is thrown.

Similarly, for objects containing other objects, you can include the object directly as a member, so instead of:

class Containing {
    Contained* member;
};

you can do

class Containing {
    Contained member;
};

In this case the memory for contained member is inside the containing object and will be deallocated when the containing object is deallocated, additionally, if the contained member was initialized during the containing object's construction, but the containing constructor then threw an exception, it is guaranteed that the contained member will be properly destroyed, including its own destructor being called, even though the containing object's destructor isn't called.

As there are no pointers involved in this, you don't have to worry about dangling or null pointers, and you get the additional advantage of reduced time and memory overhead.

The disadvantages are: no recursion in data structures (so for lists, trees etc. you need to use pointers), no polymorphism (a pointer to SomeType may point to an object of SomeType or a type derived from SomeType, an automatic variable of type SomeType can only be of that specific type), and no delayed initialization (this is especially important for class data memebers, whose constructor parameters must always be given in the containing class initializer list, while a pointer can be (re)assigned at any time.

Where dynamic objects must be used, you need to rely on design to make sure your dynamic objects are deleted. The typical pattern for this is the concept of an 'owner' - being an entity responsible for deleting dynamic objects. In this concept, every dynamic object has one and only one 'owner', which is a currently executing function or another object that holds a pointer to the owned object. Thus there may be many pointers to one object, but only one is the owning pointer. This is applicable in many cases: a function that creates a dynamic object that lives only as long as the function runs will own that object, meaning there must be code in the function itself that does the delete. In any type of hierarchical data structures (like trees) a 'parent' object can own its 'children'. Some dynamic data structures, like linked lists, can be wrapped in objects that own their dynamic nodes and are responsible for both creating and deleting them, in this example when an element is added to or removed from the list.

In more complex cases ownership can be transferred between various pieces of code. For example a collection of dynamic objects may assume ownership of objects created outside of it when they are added with an insert method, and relinquish that ownership with an extract method with get-and-remove semantics (pop, dequeue...). A function which creates dynamic objects and return pointers to them may pass ownership to the caller, and so on.

With objects maintaining ownership of dynamic objects, you will always want to ensure they are deleted in the destructor, because if it doesn't happen, when the owner gets destroyed, the object owned will remain without an owner, meaning it will never be deleted, effectively becoming a memory leak. The owner can also delete the owned object before it is destroyed itself, which is useful in many circumstances. One caveat though: make sure that the owner is not left with a dangling pointer that it would consider to be pointing at a valid object and try to destroy again. In some cases, you destroy an owned object when you're replacing it with a new one, in which case you don't have this problem, as the owning pointer will now point to the new owned object, which is also valid. In other cases you will want to set the owning pointer to 0, so the object know it does not own anything under that pointer any more (it is also safe to call delete on null pointer).

There are a couple of problems with using manual deletes in function body or destructors to maintain ownership: first, this ownership is not expressed in code, you have to manage it separately, which is error-prone (as the compiler will and cannot detect any mistakes here). This is further complicated by the exception issue I mentioned above: it is hard, and again, susceptible to errors, to write code so that delete will be called no matter where an exception is thrown.

Smart pointers in boost and standard library, mentioned in other answers, help explicitly express ownership semantics in an exception-safe manner. STL's auto_ptr and boost scoped_ptr have strict ownership semantics described above, respectively with and without the ability to transfer ownership. If you are fortunate enough to use the current standard C++, unique_ptr is a replacement for auto_ptr that does away with some of its problems. The shared_ptr of new standard STL, boost and TR1 has 'shared ownership' semantics, where an object has several 'owners' and is destroyed when the last owner lets go of it. There are advantages and caveats to using each of these smart pointer types, which you should read up on before using them.

AndrzejJ
  • 720
  • 5
  • 11
1

The best way of deallocating memory is not doing it manually, But by using RAII/SBRM, wherein, each resource by itself takes care of deallocating the resources acquired by it.

Use smart pointers.

Community
  • 1
  • 1
Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • what do you mean by smart pointers? The code is already written. As I;ve mention I have a .h and a .cpp files. I want ot create a static library, but befire this I want to resolve the problem with memory leaks in my code. – sunset Aug 23 '11 at 09:16
  • should I use inside each class besides the constructor a destructor? this means that the client that uses the library is responsable for deallocating the memory. – sunset Aug 23 '11 at 09:17
  • @sunset: you're going to change the code anyway, so why not switch to smart pointers and RAII? It will make your life much easier. – Fred Foo Aug 23 '11 at 09:18
  • @sunset: By smart pointers he means `std::shared_ptr` and `std::unique_ptr`, or if your compiler doesn't support C++11 `boost::shared_ptr` and `boost::scoped_ptr`. – Sven Aug 23 '11 at 09:21
  • @sunset: I think you need to read the link which i posted in the answer to know what we are suggesting. Also, if you do not want to change the code to use **RAII** (though I strongly suggest you should), use a memory profiling and leak detecting tool like valgrind to detect memory leaks in your program and deallocate that those leak causing pointers by calling `delete`. – Alok Save Aug 23 '11 at 09:22
  • i am just reading the link. THX a lot. for compliation i am using g++ – sunset Aug 23 '11 at 09:24
1

In C++, a very important concept when allocating dynamic memory is ownership. The owner is responsible to delete an object when it is no longer needed. When passing pointers as function arguments or return values, it is crucial to document if the ownership is transferred:

class Foo {
public:
    void setHandler(Handler* handler);
    Bar* getBar();
};

Does Foo::setHandler() take ownership of the given handler? If so, it is Foo's task to ensure that the object is deleted at some point. Otherwise, the caller stays the owner.

Similarly, is a user of Foo::getBar() supposed to delete the Bar* it receives, or will Foo continue to own it?

Ferdinand Beyer
  • 64,979
  • 15
  • 154
  • 145
  • what do you mean by it is the foo's task to delete the object? – sunset Aug 23 '11 at 09:27
  • and one more question: what if inside the method setHandler I am creating a pointer to another class? SHould I use delete pointer before the method is closed? – sunset Aug 23 '11 at 09:28
  • @sunset, there's no easy answer to that question. It all depends on what you do with the pointer. You delete a pointer after the last time you use it. Also you must ask yourself do you actually need to create a pointer? Why create a pointer when you can create an object? In other words instead of `Class *x = new Class();` why not just do `Class x;`. Neither of these is right or wrong, it just all depends on what you are trying to do. You have to think about the *lifetimes* of the objects you create. – john Aug 23 '11 at 09:33
0

Knowing when to delete pointers is very difficult. Use smart pointers to do the work for you, boost::shared_ptr is the obvious place to start looking,

john
  • 85,011
  • 4
  • 57
  • 81