0

I have programmed a little software and wanted to create a new object on the heap. In the class member function I thus have

void  gShop::CreateCustomer(int type, int number)
    {
    vSlot[number] = new gCustopmer(type);
    vSlot[number]->itsContactToShop=itsShopNumber;
    vSlot[number]->itsNumber=number;
    }

where vSlot is a vector of pointers to customer objects. I have a (here: abbreviated) class gShop, in essence:

class gShop : public gBranch
   {
   public:
       gShop(): vSlot(100){}
      ~gShop(){}   

       std::vector <gCustomer*>   vSlot;
       ...
   }

and in main I call the member function to create new customers..

  vShop[0].CreateCustomer(TYPE_M20, 1);
  vShop[0].CreateCustomer(TYPE_F40, **2**);//EDIT:typo previously here. I intend to create customers by reading a file later on.

  std::cout<< "1" << vShop[0].vSlot[1]->itsTypeString << std::endl;
  std::cout<< "2" << vShop[0].vSlot[2]->itsTypeString << std::endl;

I know that I have created with "new" two objects on the "heap" (if I handle the terminology right - sorry I am quite new to programming without formal education) and I also have two pointers to that objects stored in a vector within the object shop[0].

My question is I heard the saying that for every new there is a delete. Where do I have to delete this object? I am actually not planning on deleting any created shop or customer object in the program.

Secondly, is this code so far okay in terms of not causing memory leaks? I am a bit worried that I created the new object within a member function class, so should I try to implement delete in the destructor to gShop and set the pointer to NULL - in the theoretical case I should ever want to delete shop[0]?

Many thanks.

trincot
  • 317,000
  • 35
  • 244
  • 286
CodeTrek
  • 435
  • 1
  • 3
  • 10

4 Answers4

3

In the way you have written your code, you should expand you destructor implementation for gShop to iterate over the vector<> vSlot and delete each element. Because you have memory that has to be managed in this way to prevent a memory leak, you are also required to follow the Rule of Three. So, you also need to do something during copy construction (a deep copy), and you have to do something for the assignment operator (cleanup up the vector<> that is about to be copied over, and do a deep copy).

You can avoid these issues, and allow your object to use the default destructor, copy constructor, and assignment operator, by using a smart pointer instead. For example:

    std::vector<std::shared_ptr<gCustomer>> vSlot;

When you create an element in the vSlot, you could use make_shared():

    vSlot[number] = std::make_shared<gCustopmer>(type);

The smart pointer will delete the memory for you when there are no more references to the memory. If you don't have C++.11 available to you, you can use boost::shared_ptr instead.

The smart pointer will make it so that a copy of your gShop will share the same pointers as the original gShop it copied from. The smart pointer makes that situation okay, since there will not be multiple delete calls on the same memory. However, if you need the deep copy semantics, then you would still need to implement your own copy constructor and assignment operator to make the deep copies.

If you want something that will clean up automatically like a smart pointer, but still give you a deep copy with the default copy constructor and default assignment operator, then you can try to use boost::optional.

If you are using g++ version 4.4 or higher, then you should be able to enable C++.11 features with -std=gnu++0x, or -std=c++0x if you don't want GNU extensions. If you have g++ 4.7 or higher, then the options are -std=gnu++11 or -std=c++11.

Community
  • 1
  • 1
jxh
  • 69,070
  • 8
  • 110
  • 193
  • You should fix the `>>` to `> >`. Also, good work on mentioning deep copying. – Cramer Oct 07 '13 at 23:15
  • @Cramer There is nothing to fix. `std::shared_ptr` is C++11 so closing several templates in a row without space `>>` is perfectly fine. – syam Oct 07 '13 at 23:20
  • Thanks, I heard about boost and it would be lovely to use its many functions - especially fast iterating of vector elements - but I have an old version of codeblocks that doesn't have it. I don't know how to install it and when I start upgrading to a newer version my program is not running anymore (I have a lot of OPENGL in it) with errors that seem to be generally unresolved :/ I see it as a good exercise though. – CodeTrek Oct 07 '13 at 23:21
  • @syam Thanks, I didn't realise that was now allowed. Nice to know! – Cramer Oct 08 '13 at 00:00
  • @user2856452: I updated my answer with what you need to do to be able to use some C++.11 features, even with an older compiler. The answer you accepted does not warn you about the dangers of dealing with bare pointers in your class. It is okay to accept that answer (my answer also covered that possibility), but please also keep the Rule of Three in mind (the link is also in my answer). – jxh Oct 09 '13 at 00:30
  • Hi, many thanks! However, I don't have boost (I've mentioned that before in a previous commet) as don't have it in my include directory too. I use gcc 3.4.5 with codeblocks that I installed ages ago and I have a portability problem if I try different platforms or upgrade the current platform. I really liked the other guys answer as it gave me exactly what I wanted. Obviously you elaborated more, but it is like I ask how to park with my FIAT and I get an answer like better to use a Mercedes with autparking navigation. ;) – CodeTrek Oct 09 '13 at 01:33
  • ..and really loved the rule of three... I knew about that one. However, the program code that I gave is really a tiny snippet. The total program has over 8000 lines and I have also copy constructors and destructors. I just put a few lines up to be able to ask my question. – CodeTrek Oct 09 '13 at 01:36
0

Yes any memory that is allocated from the heap must be freed! With the "new" you are allocating memory from the heap that is the sizeof gCustomer. A good place to deallocate your memory would be in your destructor: ~gShop() Memory leaks are caused by not deallocating your memory, although once your close your program all the memory is freed automatically.

SirGregor
  • 1
  • 3
0

Every time you create object with new piece of memory is taken from the heap. Only way to communicate with this memory is via pointer you got from new. When you use delete on that pointer memory is freed and may by used for other purposes. So when you lose pointer you create memory leak.
In your code the right way is:
Start with the vector with null pointers. When you create object in exact position check pointer. If it is not null you already have object and have to delete it (or maybe throw error)

void  gShop::CreateCustomer(int type, int number)
{
    if(vSlot[number] != 0) {
         delete vSlot[number];
         vSlot[number] = 0;
    }
    vSlot[number] = new gCustopmer(type);
    vSlot[number]->itsContactToShop=itsShopNumber;
    vSlot[number]->itsNumber=number;
}

When the vector is destroyed you need to free all memory within it. So you destructor will be something like this:

gShop::~gShop() {
    for(int i = 0; i < (int)vSlot.size(); ++i) {
          delete vSlot[i];
    }
}
conf1ict
  • 81
  • 4
  • That's cool. So you mean like vSlot(100, NULL) instead of vSlot(100)? And then I replace it check with an if statement if its NULL as you have shown? – CodeTrek Oct 07 '13 at 23:18
  • no vectors already init it with nulls. But when you have raw poiters you should init they with null (its good way to write). Sorry i mistakes (and correct answer) in you create function. You check if pointers not null object alredy exists. – conf1ict Oct 07 '13 at 23:21
  • 1
    When `CreateCustomer()` deletes an existing item, you should NULL that slot of the vector, in case the subsequent `new` raises an exception. – Remy Lebeau Oct 07 '13 at 23:28
  • btw. do you know I would declare vSlot within the class with 100 stanard constructor customers instead of NULL? – CodeTrek Oct 08 '13 at 00:07
  • it's possible. if you store objects in vector you don't have to worry about memory managment. No need to 100 objects at start add they by `push_back` and etc. But can't store delivered classes. – conf1ict Oct 08 '13 at 00:25
  • In fact I would like to have a dummy no customer object in the vector. I won't be bothered by memory management and also it fits my purpose. How do I initialize it in the class, or do I have to do it manually in the constructor {...} by looping it in? – CodeTrek Oct 08 '13 at 00:45
  • just provide default constructor for the customer class – conf1ict Oct 08 '13 at 00:49
  • Didn't work.. I tried gShop(): vSlot(100, gCustomer()){..} but I believe this is totally wrong and my prog crashes.. Do I have instead to do it in the { } of gShop manually adding each object? – CodeTrek Oct 08 '13 at 00:55
  • keep `:vSlot(100)`. vector calls the gCustomer::gCustomer() for each object itself. Provide default initialization there. – conf1ict Oct 08 '13 at 00:59
  • Are you sure it initializes? I checked my member data and it is not as what I was hoping for. In fact it crashes when I tried to access a member variable but it returns NULL. EDIT: ohh well, it doesn't matter, I did it manually and all works fine. Thx – CodeTrek Oct 08 '13 at 01:03
  • Sorry, my bad. I misunderstand. You need for loop in your constructor to create each object with new – conf1ict Oct 08 '13 at 01:09
0

gShop needs to delete the gCustomer objects that it creates. It can do that in its destructor, eg:

class gShop : public gBranch
{
public:
    ...
    ~gShop()   
    ...
};

gShop::~gShop()
{
    std::vector<gCustomer*>::iterator iter = vSlot.begin();
    std::vector<gCustomer*>::iterator end = vSlot.end();
    while (iter != end)
    {
        delete *iter;
        ++iter
    }
}

Or:

void deleteCustomer(gCustomer *customer)
{
    delete customer;
}

gShop::~gShop()
{
    std::for_each(vSlot.begin(), vSlot.end(), deleteCustomer);
}

However, you would still have a memory leak. You are storing two separate gCustomer objects in the same vSlot[1] slot of vShop[0], so you are losing track of one of your customers. I suspect you meant to do this instead:

vShop[0].CreateCustomer(TYPE_M20, 1);
vShop[0].CreateCustomer(TYPE_F40, 2); // <-- was previously 1

std::cout<< "1" << vShop[0].vSlot[1]->itsTypeString << std::endl;
std::cout<< "2" << vShop[0].vSlot[2]->itsTypeString << std::endl;

That being said, you should re-think your design and let the STL handle all of the memory management for you, eg:

class gShop : public gBranch
{
public:
    std::vector <gCustomer> vSlot;
    ...
};

void gShop::CreateCustomer(int type)
{
    vSlot.push_back(type);
    gCustomer &cust = vSlot.back();
    cust.itsContactToShop = itsShopNumber;
    cust.itsNumber = vSlot.size()-1;
}

vShop[0].CreateCustomer(TYPE_M20);
vShop[0].CreateCustomer(TYPE_F40);


// remember that vectors are 0-indexed
std::cout<< "0" << vShop[0].vSlot[0].itsTypeString << std::endl;
std::cout<< "1" << vShop[0].vSlot[1].itsTypeString << std::endl;

Or:

class gShop : public gBranch
{
public:
    std::vector <std::shared_ptr<gCustomer> > vSlot;
    ...
};

void gShop::CreateCustomer(int type)
{
    std::shared_ptr customer = std::make_shared<gCustomer>(type);
    customer->itsContactToShop = itsShopNumber;
    customer->itsNumber = vSlot.size();
    vSlot.push_back(customer);
}

vShop[0].CreateCustomer(TYPE_M20);
vShop[0].CreateCustomer(TYPE_F40);

std::cout<< "0" << vShop[0].vSlot[0]->itsTypeString << std::endl;
std::cout<< "1" << vShop[0].vSlot[1]->itsTypeString << std::endl;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • yes, should have been "2" - my mistake when typing. I also actually don't want to delete any element of vSlot as I rather fill them with "dummy" customers. I don't get the shared_ptr? Is this a new C++ syntax? I started the whole program years ago with an older version together with OpenGL. It has several thousand lines of code. I am stuck with that version I believe and cannot use shared_ptr. – CodeTrek Oct 07 '13 at 23:35
  • [`shared_ptr`](http://en.cppreference.com/w/cpp/memory/shared_ptr) is new in C++11. For older versions of C++, you can use [`boost::shared_ptr`](http://www.boost.org/doc/libs/1_54_0/libs/smart_ptr/shared_ptr.htm) instead. – Remy Lebeau Oct 08 '13 at 00:28
  • I don't have even boost in my includes! I can't make the code work with a newer version.. I don't get compile errors but really nasty build errors with OpenGL. When I researched on it, it was maintained as unresolved. So I keep working with the older code.. – CodeTrek Oct 08 '13 at 00:50