0

I have this class:

class stringlist {
public:
    typedef std::string str;
    void push(str);
    void pop();
    void print();
    void resize(size_t);
    size_t capacity();
    size_t size();
    stringlist() : N(15) {}
    stringlist(size_t sz) : N(sz) {}
private:
    size_t N;
    str* container = new str[N];
};

The following is a test program to test out the class:

stringlist slist(16);
slist.push("One");
slist.push("Two");
slist.push("Three");
std::cout << "Capacity: " << slist.capacity() << std::endl;
std::cout << "List size: " << slist.size() << std::endl;
slist.print();

I am not sure when and how the dynamically managed memory should be deleted. Would I need to call a destructor, ~stringlist() { delete [] container; }? Since new is used to create a data member, I am not sure if I am allowed to delete the member.

Mars
  • 4,677
  • 8
  • 43
  • 65

3 Answers3

3

There is a rule of thumb in C++:

For every new, a delete.

Your code is no exception. You have newed something; you must delete it.

Since container was newed in stringlist's constructor, you should delete it in stringlist's destructor.

You do not call destructors directly.1 Instead, you simply allow the destructor to be called in the normal deallocation of the object, be that via delete or via automatic (ie, "stack") destruction.


1 You do not call destructors directly.: Usually. An exception is when using placement-new, which you're not doing here. If you don't know if you need to use placement-new then you don't.

John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • So in a nutshell in my implementation, adding `~stringlist() { delete [] container; }` should solve the problem? – Mars Nov 06 '13 at 16:53
  • @Dochevsky: Looks about right. I would maybe make the destructor `virtual`, and by the way your `new` looks spurrious. It needs to be in a constructor. – John Dibling Nov 06 '13 at 16:56
  • Is that a matter of good convention or is that a necessary requirement? Seems to work as desired as it is. Will the destructor not work the way it should if the `new` was not in the constructor? – Mars Nov 06 '13 at 17:03
  • In C++03 it is absolutely necessary for the `new` to be in the constructor. In C++11 I'm not sure. – John Dibling Nov 06 '13 at 17:05
2

You mainly have two situations:

  • Variable allocated on the stack. It will be automatically deallocated by the compiler when it goes out of scope. Pay attention to not access the variable (e.g., through a pointer) when it has been deallocated.

  • Variable allocated on the heap through the new statement. Here you have to explicitly call delete when the variable is not needed anymore. Pay attention to not create memory leaks (i.e., a variable allocated through new which is not refereced anymore so it cannot be deleted).

Your code is an example of the first kind.

For the second case, if you don't want to have to remember which variables need to be deleted (and when) you can use smart pointers (available in the Boost library or natively in the C++11 standard). See here for more information.

Community
  • 1
  • 1
Claudio
  • 10,614
  • 4
  • 31
  • 71
2

Simple rules:

  • pair any new/new[] with a delete/delete[]
  • or delegate deletion to a smart pointer (eg std::unique_ptr or std::shared_ptr)

Fixing your case:

stringlist() : N(15), container(new str[N]) {}
stringlist(size_t sz) : N(sz), container(new str[N]) {}
// and
~stringlist() { delete [] container; }
// and
private:
size_t N;
str* container;