4

I use extra brackets in my code. I thought when the destructor should be called after the local variable scope is ended but it doesn't work like this:

class TestClass {
public:
    TestClass() {
        printf( "TestClass()\n" );
    }
    ~TestClass() {
        printf( "~TestClass()\n" );
    }
};

int main() {
    int a, b, c;
    {
         TestClass *test = new TestClass();
    }
}

It outputs:

TestClass()

So it doesn't call the destructor of the TestClass but why? If I call it manually (delete test) it calls the destructor, right. But why it doesn't call the destructor in the first case?

JavaRunner
  • 2,094
  • 3
  • 32
  • 48
  • 1
    Because if you create an object with `new`, it can only be destructed when calling `delete` on it - it won't be destroyed by going out of scope. – Nbr44 Aug 07 '13 at 07:44
  • 2
    @Nbr44: Not exactly true. You can call the destructor directly. Of course, this won't free the memory, but it will destroy the object. Then the only way to properly free the memory without undefined behavior is by constructing another object of the same type in its place (via placement new) and calling delete on that. – Benjamin Lindley Aug 07 '13 at 08:02

3 Answers3

14
TestClass *test = new TestClass();

You using new which creates a dynamically allocated object (most likely placed on the heap). This type of resource needs to be manually managed by you. By managing, you should use delete on it after you have done using it.

{
     TestClass *test = new TestClass();
     // do something
     delete test;
}

But for the most of your purposes and intents, you just have to use automatic-storage objects, which frees you the hassle of having to manually manage the object. It would also most likely to have better performance especially in short-lived objects. You should always prefer to use them unless you have a really good reason not to do so.

{
     TestClass test;
     // do something
}

However, if you need the semantics of dynamically allocated objects or that of pointers, it will always be better to use some mechanism to encapsulate the deletion/freeing of the object/resource for you, which also provides you additional safety especially when you are using exceptions and conditional branches. In your case, it would be better if you use std::unique_ptr.

{
     std::unique_ptr<TestClass> test(new TestClass());
     // auto test = std::make_unique<TestClass>();  in C++14

     // do something (maybe you want to pass ownership of the pointer)
}


The following is a relevant link to help you decide whether to use automatic storage objects or dynamically allocated objects: Why should C++ programmers minimize use of 'new'?
Rakete1111
  • 42,521
  • 11
  • 108
  • 141
Mark Garcia
  • 16,438
  • 3
  • 50
  • 93
  • 1
    "You should always prefer to use this unless you have a really good reason not to do so." -- but why it's so important not to use pointers here? Because you may forget to delete it or some other important reasons? – JavaRunner Aug 07 '13 at 07:58
  • 1
    @JavaRunner Yes. And they are most prone to errors, give you the unnecessary indirection which is likely to hamper performance, and it's ugly to have code with a lot of `*`s and `delete`s on it. – Mark Garcia Aug 07 '13 at 08:00
  • 2
    @JavaRunner another issue, besides the clouded lifetime, is clouded ownership: it can become difficult to track who owns a pointer to a dynamically allocated object, that is, who is in charge of deleting it. Value semantics are easier to reason than reference semantics. – juanchopanza Aug 07 '13 at 08:04
  • @JavaRunner I recommend you to learn [RAII](https://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization), which is a really good tool in programming in C++. Also read this SO question: http://stackoverflow.com/questions/395123/raii-and-smart-pointers-in-c – Mark Garcia Aug 07 '13 at 08:14
  • You chose a bad example using `unique_ptr`, because it results in exactly the same semantics as using a local variable. It might be appropriate if, for example, you were using polymorphism (and the actual type wasn't known until runtime), but the most frequent reason for allocating dynamically is precisely because the required lifetime doesn't correspond to any given scope, and that the object must be destructed explicitly, at a moment which depends on program logic, and not on lexical considerations like scope. – James Kanze Aug 07 '13 at 08:14
  • @juanchopanza Generally (and there are exceptions): you use dynamic allocation only when an object has identity and a specific lifetime determined by program logic. Without identity, as you say, you copy, rather than allocate dynamically. – James Kanze Aug 07 '13 at 08:17
  • @JamesKanze However, he *might* be passing ownership of the object to another function, though he didn't specify. I included that just if he wants to do something as said (*"I really want to use pointers!"* :) ). (Sorry, I initially misunderstood your statement). – Mark Garcia Aug 07 '13 at 08:20
  • @MarkGarcia One certainly should learn RAII, and use it extensively. Although I'm not sure the name is appropriated, since most of the uses I make of it don't really involve resources (and of course, the key isn't "initialization", but the clean-up in the destructor). But it depends itself on object lifetime, and is rarely appropriate for managing another objects lifetime (except maybe temporarily). Generally, if you need to dynamically allocate an object, it is because its lifetime cannot conform to any lexical scope, which means that RAII isn't applicable. – James Kanze Aug 07 '13 at 08:36
  • @MarkGarcia Yes. It's hard to say why he wants to use a pointer, since it clearly isn't appropriate for the little bit of code we see. The fact that he seems surprised that the destructor wasn't called, however, makes me think that he's coming from a Java background, and simply thinks you have to allocate everything dynamically. I just thought it would be a little better (because the answer is very good already) if your pointer example somehow indicated _why_ you might use the pointer: make it a `shared_ptr`, for example, or initialize it with a derived class, or ... – James Kanze Aug 07 '13 at 08:41
  • @JamesKanze I must add that the use of `std::unique_ptr` there is mostly to emphasize the additional safety that smart pointers, and generally RAII, brings. Also, the important distinction that we should make here is between pointers and automatic variables. Well, one of `std::unique_ptr`'s role in there is to somehow just brings the former slightly closer to the latter. – Mark Garcia Aug 07 '13 at 08:42
  • @JamesKanze *"because the answer is very good already"* Thank you. *"indicate why you might use the pointer"* I will, thanks again for the suggestion. – Mark Garcia Aug 07 '13 at 08:44
  • @JamesKanze I'm sorry, but while editing, I realized that what you suggest could not be summarized just in a paragraph or two. As my time is currently constraining me on the extensiveness of the improvement, I'll just leave the answer as-is. I'll just share some relevant links. Again, I really wish I could make what you suggested. – Mark Garcia Aug 07 '13 at 09:09
8

Because you have a pointer to a dynamically allocated object. Only the pointer goes out of scope, not the object it points to. You have to call delete on the pointer in order for the pointee's destructor to get called.

Try with an automatic storage object instead:

{
  TestClass test;
}

Here, the destructor will be called on exiting the scope.

The use of raw pointers to dynamically allocated objects in C++ is discouraged because it can easily lead to resource leaks like the one shown in your code example. If pointers to dynamically allocated objects are really needed, it is wise to handle them with a smart pointer, rather than to attempt to manually deal with their destruction.

juanchopanza
  • 210,243
  • 27
  • 363
  • 452
3

This answer is good enough but just to add some more.

I see you have been coded with Java. In C++ to create variable/object in stack keyword new is not needed. Actually when you use keyword new your object is creating in heap and it doesn't destroys after leaving scope. To destroy it you need to call delete in your case delete test;

In such a structure as yours, after leaving scope you just lose pointer what points into object, so after leaving scope you cannot free memory and call destructor, but eventually OS call destructor just after exit() instruction is executed.

To sum up C++ != Java

Community
  • 1
  • 1
ST3
  • 8,050
  • 2
  • 62
  • 85