3

i am using a map to store an pair (int and class) using the following:

#include <iostream>
#include <utility>
#include <map>
using namespace std;

class abstractclass{...};

class derivedclass : public abstractclass{...};

typedef map<int,abstractclass*> dBase;

int main(){
    dBase db;
    db.insert(pair<int,abstractclass*>(123,new derivedclass));
    db.insert(pair<int,abstractclass*>(124,new derivedclass));
}

How do i then delete the memory allocated to this? I need to be able to use insert a user defined amount of times so a method that can delete every database entry is preferred, thanks!

If theres a way i can do this without using memory allocation that would also be useful

6502
  • 112,025
  • 15
  • 165
  • 265
Eduardo
  • 6,900
  • 17
  • 77
  • 121

3 Answers3

11

Due to your class hierarchy you obviously can't just store your abstractclass objects by value in the map or you'd run into the infamous object slicing problem.

The usual way to solve this problem is to use smart pointers, eg. std::unique_ptr or std::shared_ptr (both C++11, for C++03 never use std::auto_ptr in containers since it is broken, but you can safely use the boost smart pointers instead).

So your map type would become eg. std::map<int, std::unique_ptr<abstractclass>>. Then you don't need to bother any more about deleting the objects, when they are removed from the map the smart pointer will automatically take care of it.

Another solution is to delete all the items yourself (like @MarkB said) but this is very error prone so smart pointers are usually preferred when possible.

Community
  • 1
  • 1
syam
  • 14,701
  • 3
  • 41
  • 65
4

As long as your abstractclass has a virtual destructor, you can simply iterate over all the items in the container and delete the second component of the item to free the memory. There are multiple ways of doing this: For example for loop, or for_each with a functor or lambda.

EDIT: Upon further review, it appears that the map has ownership here, and your life will be much easier if you either use a map of shared_ptr (from boost or C++11), or use a boost::ptr_map instead. Then you don't have to worry about cleaning up the map at all - you can just use db.clear(); and all the items will be cleaned up automatically. Either of these containers would also help with managing memory in the face of inserting duplicate items.

Mark B
  • 95,107
  • 10
  • 109
  • 188
  • So would this work: `for(dbIT = db.begin(); dbIT != db.end();++dbIT){ delete dbIT->second; }` where dbIT is `dBase::iterator dbIT` – Eduardo May 06 '13 at 14:16
  • is there a neat way to delete a duplicate entry on insert call? – spiritwolfform May 06 '13 at 14:20
  • @10WaRRioR01: no, you have to take care of that yourself, which can quickly turn into a headache (`insert` can throw so you need to write exception-safe code that will delete your `new`'ed object only if the insertion failed, either a smart pointer or a `try/catch`, it complicates the code quite a lot). – syam May 06 '13 at 14:25
  • @clairharrison: Yes this is the idea. However, avoiding memory leaks is not just a matter of deleting the objects in the map at the end of the program, there are lots of other places you need to take care of and you need to be really careful about that. – syam May 06 '13 at 14:30
  • I would prefer std::unique_ptr to std::shared_ptr unless the objects really do have shared ownership. – Adrian McCarthy May 18 '13 at 19:30
3

You can use a smart pointer in your container:

#include <iostream>
#include <utility>
#include <map>
#include <memory>
using namespace std;

class abstractclass{...};

class derivedclass : public abstractclass{...};

typedef map<int,shared_ptr<abstractclass>> dBase;

int main(){
    dBase db;
    shared_ptr<abstractclass> ptr1(new derivedclass);
    shared_ptr<abstractclass> ptr2(new derivedclass);
    db.insert(pair<int,shared_ptr<abstractclass>>(123,ptr1));
    db.insert(pair<int,shared_ptr<abstractclass>>(124,ptr2));
}

The shared pointers will give a little bit of overhead here, but the advantages are:

  1. You don't have to care about deleting your objects - they will get deleted as soon as the map is destroyed.
  2. You can safely create a new object and try to insert it into the map - if the insertion fails (even with exception), the allocated object will be safely destroyed.
  3. You can insert an empty pointer and reset() it later with an actually created value (i.e. to not actually create an object, if a value with such key already exists)
DarkWanderer
  • 8,739
  • 1
  • 25
  • 56
  • Thanks, ill use that in future, i need to prove i know how to delete allocated memory for this project though but your method will be more use in the long run – Eduardo May 06 '13 at 14:48
  • Well, if you explain to whoever checks your project how and why you use smart pointers, that'd give you even more points :) – DarkWanderer May 06 '13 at 15:28