0

I'm sure this is answered somewhere, but I'm lacking the vocabulary to formulate a search.

#include <iostream>

class Thing
{
public:
  int value;
  Thing();

virtual ~Thing() { std::cout << "Destroyed a thing with value " << value << std::endl; }
};

Thing::Thing(int newval)
{
  value = newval;
}

int main()
{
  Thing *myThing1 = new Thing(5);
  std::cout << "Value 1: " << myThing1->value << std::endl;

  Thing myThing2 = Thing(6);
  std::cout << "Value 2: " << myThing2.value << std::endl;

  return 0;
}

Output indicates myThing2 was destroyed, my myThing1 was not.

So... do I need to deconstruct it manually somehow? Is this a memory leak? Should I avoid using the * in this situation, and if so, when would it be appropriate?

redux
  • 1,120
  • 10
  • 20

5 Answers5

5

The golden rule is, wherever you use a new you must use a delete. You are creating dynamic memory for myThing1, but you never release it, hence the destructor for myThing1 is never called.

The difference between this and myThing2 is that myThing2 is a scoped object. The operation:

Thing myThing2 = Thing(6);

is not similar at all to:

Thing *myThing1 = new Thing(5);

Read more about dynamic allocation here. But as some final advice, you should be using the new keyword sparingly, read more about that here:

Why should C++ programmers minimize use of 'new'?

Community
  • 1
  • 1
Fantastic Mr Fox
  • 27,453
  • 22
  • 81
  • 151
  • You really ought to work on the language. Thing2 is not statically created object. Nothing here will 'create copy assignment operator' (which does not exist). 'Somewhat equivalent' is unclear. – SergeyA Jan 21 '16 at 18:57
  • @SergeyA I agree on 2/3, and fixed. But [copy assignment operator](http://en.cppreference.com/w/cpp/language/copy_assignment) is definitely a thing. – Fantastic Mr Fox Jan 21 '16 at 19:06
  • it is a thing, no one argues. But that line `Thing *myThing1 = new Thing(5);` simply **does not** create a copy-assignment operator which does not exist. It does not even call an existing one. Don't make me to retract my upvote ;) – SergeyA Jan 21 '16 at 19:33
  • this is the quote: *Thing myThing2 = Thing(6) will create an implicit copy assignment operator*. This statement is not true. – SergeyA Jan 21 '16 at 20:19
  • @SergeyA yep, ok. I looked it all up. Thanks for your help. Calls standard constructor. – Fantastic Mr Fox Jan 21 '16 at 21:51
2

myThing1 is a Thing* not a Thing. When a pointer goes out of scope nothing happens except that you leak the memory it was holding as there is no way to get it back. In order for the destructor to be called you need to delete myThing1; before it goes out of scope. delete frees the memory that was allocated and calls the destructor for class types.

The rule of thumb is for every new/new[] there should be a corresponding delete/delete[]

NathanOliver
  • 150,499
  • 26
  • 240
  • 331
1

You need to explicitly delete myThing1 or use shared_ptr / unique_ptr.

delete myThing1;
George Houpis
  • 1,709
  • 1
  • 7
  • 5
1

The problem is not related to using pointer Thing *. A pointer can point to an object with automatic storage duration.

The problem is that in this statement

Thing *myThing1 = new Thing(5);

there is created an object new Thing(5) using the new operator. This object can be deleted by using the delete operator.

delete myThing1;

Otherwise it will preserve the memory until the program will not finish.

Vlad from Moscow
  • 224,104
  • 15
  • 141
  • 268
1

Thing myThing2 = Thing(6);

This line creates a Thing in main's stack with automatic storage duration. When main() ends it will get cleaned up.

Thing *myThing1 = new Thing(5);

This, on the other hand, creates a pointer to a Thing. The pointer resides on the stack, but the actual object is in the heap. When the pointer goes out of scope nothing happens to the pointed-to thing, the only thing reclaimed is the couple of bytes used by the pointer itself.

In order to fix this you have two options, one good, one less good.

Less good: Put a delete myThing1; towards the end of your function. This will free to allocated object. As noted in other answers, every allocation of memory must have a matching deallocation, else you will leak memory.

However, in modern C++, unless you have good reason not to, you should really be using shared_ptr / unique_ptr to manage your memory. If you had instead declared myThing1 thusly:

shared_ptr<Thing> myThing1(new Thing(5));

Then the code you have now would work the way you expect. Smart pointers are powerful and useful in that they greatly reduce the amount of work you have to do to manage memory (although they do have some gotchas, circular references take extra work, for example).

Donnie
  • 41,533
  • 8
  • 62
  • 82