-1

I'm new to destructors, and the tutorials i've been following have been pretty clear up until this point. What actually happens when a destructor is called? Why do I still get values from a destroyed object?

class Box {

public: 
    Box(double l = 2.0, double b = 2.0, double h = 2.0) {   //Constructor
        cout << "Box Created" << endl;
        length = l;
        breadth = b;
        height = h;
    }
    ~Box() {
        cout << "Box Destroyed" << endl; // Box Destructor
    }
        double volume() {
            return length*breadth*height;
        }

private:
    double height;
    double breadth;
    double length;

};
void main() {

    Box Box1(10, 15, 5);    //Constructors used
    Box Box2(5, 15, 20);

    cout << "Box1.volume: " << Box1.volume() << endl;
    cout << "Box2.volume: " << Box2.volume() << endl;
    Box1.~Box(); //Destructors called
    Box2.~Box();
    cout << "Box1.volume after destruction: " << Box1.volume() << endl;
    cout << "Box2.volume after destruction: " << Box2.volume() << endl;



}
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
Samnater
  • 67
  • 5
  • 2
    You don't want to call the destructors explicitly. Since your objects are allocated on the stack, the destructors will be called automatically when your function returns. – RJM May 27 '16 at 13:10
  • @RJM Not all objects are created on the stack, but your point is still valid. – Marcus Müller May 27 '16 at 13:11
  • You should hardly ever call a destructor explicitly, and box1 & 2 here are automatic variables, in this case destructors are called when the scope leaves the bloc. – PW. May 27 '16 at 13:11
  • 2
    @PW. s/hardly never/hardly ever – NathanOliver May 27 '16 at 13:12
  • @Marcus Muller - Of course they're not all allocated on the stack. That's why I qualified my comment by pointing out that the OPs objects are allocated on the stack. :-) – RJM May 27 '16 at 13:13
  • @RJM He most likely meant the common misconception of "stored on the stack" vs. "stored on the heap". From the standard's point of view, that's an implementation detail, it does not care where the implementation stores the data. In C++ standardese, the distinction "automatic storage duration" vs. "dynamic storage duration" vs. "static storage duration" should be made instead, with normal local variables falling into the first category. – Baum mit Augen May 27 '16 at 13:36
  • @OP `void main` is wrong, `main` must always return `int`. Flowing off the end of `main` implicitly returns a "value indicating successful termination" (aka. 0). – Baum mit Augen May 27 '16 at 13:37
  • @RJM Actually, probably not. vOv – Baum mit Augen May 27 '16 at 13:38
  • @OP - *and the tutorials i've been following* -- No tutorials I know of would show calling the destructor explicitly. There is a reason for that, and you've found out why. – PaulMcKenzie May 27 '16 at 13:59

1 Answers1

-2

You never call a destructor explicitely, unless you know very well you need to because you're handling the life-time and allocation of your objects yourself, which, typically, is a not very C++-like approach.

Destructors are meant to be called automatically, when the lifetime of a C++ objects ends, for example, when an object goes out of scope.

A destructor's job is to "clean up" before the C++ runtime frees the memory associated with that object. Calling a destructor explicitly doesn't "remove" the object – it just brings the object into some kind of "Zombie" state.

As a beginner, generalizing: Don't call destructors explicitely.

Marcus Müller
  • 34,677
  • 4
  • 53
  • 94
  • 1
    Well, you would call it explicitly if you were using [placement new](https://isocpp.org/wiki/faq/dtors#placement-new). – wally May 27 '16 at 13:12
  • 3
    Wrong. You do call destructors explicitly in a certain scenarios. – SergeyA May 27 '16 at 13:13
  • See [Is calling destructor manually always a sign of bad design?](http://stackoverflow.com/questions/14187006/is-calling-destructor-manually-always-a-sign-of-bad-design) – stuartd May 27 '16 at 13:13
  • @flatmouse: There's a lot of reasons *not* to use placement new, and the linked article even states **ADVICE: Don’t use this “placement new” syntax unless you have to** – Marcus Müller May 27 '16 at 13:13
  • "unless you have to" != "never" – wally May 27 '16 at 13:14
  • Another wrong statement. Good luck creating meaningful custom allocator without using placement new. – SergeyA May 27 '16 at 13:14
  • @stuartd: agreeing with that answer: **Outside managing memory on a rather low level as above calling destructors explicitly, however, is a sign of bad design** – Marcus Müller May 27 '16 at 13:14
  • @flatmouse agreed, "never" might be a tad to strong. But OP is definitely a beginner, and people who don't write custom allocators, as mentioned by the answer stuartd linked to, shouldn't be using it. – Marcus Müller May 27 '16 at 13:15
  • @MarcusMüller Within the context of this question I would agree that it does not make sense here to call the destructor explicitly. – wally May 27 '16 at 13:16
  • And this is a 3rd wrong statement in a row. While custom allocators are one of the cases for using placement new, it is not the only one. I think, this answer should be removed. The wording is obscure and misleading. – SergeyA May 27 '16 at 13:16
  • I wonder what the standard says about the status of the object once the destructor was manually called. Undefined behavior? – wally May 27 '16 at 13:17
  • @flatmouse I'd agree to change "never" into "never (unless you know very well you need to because you're handling the life-time and allocation of your objects yourself, which, typically, is a not very C++-like approach)". Would that appease you? (I kind of doubt I'll appease Sergey) – Marcus Müller May 27 '16 at 13:17
  • 1
    @MarcusMüller, your hunch is correct. Cosmetic change as above wouldn't make it a good answer, and there is already a very good duplicate. I counsel removal. – SergeyA May 27 '16 at 13:18
  • @SergeyA the duplicate aspect is a valid argument! – Marcus Müller May 27 '16 at 13:19
  • @MarcusMüller I think it would appease the c++ forces that us mere mortals can only dream about. It would also make it the only answer where others were to timid to answer. :) – wally May 27 '16 at 13:19
  • @flatmouse, the standard is very clear on this part: *Once a destructor is invoked for an object, the object no longer exists* – SergeyA May 27 '16 at 13:20
  • 1
    So, I'm stuck between SergeyA's pretty wise approach of "better say nothing than something questionable if there's another, good, answer to a similar question already" and flatmouse's "giving an answer with explicit advise not to shoot one's own foot to a beginner question might be worth the frowning it induces with people who actually know their C++". – Marcus Müller May 27 '16 at 13:21
  • @SergeyA: re: standard: is that a "passive" *is invoked (by the runtime after lifetime has ended)* or a "temporal" *is invoked (no matter who invoked it*? Could you give us a link to the standard text? – Marcus Müller May 27 '16 at 13:22
  • @MarcusMüller, don't worry too much about it :) Just follow your heart. – SergeyA May 27 '16 at 13:23
  • @MarcusMüller If you answer adds something new you can always add it to the dupe target so everyone gets to see it instead of it sitting here in isolation. – NathanOliver May 27 '16 at 13:23
  • @MarcusMüller, yes, you can find this wording in 12.4 / 15. I do not have linkable standard in front of me. – SergeyA May 27 '16 at 13:24
  • @SergeyA Here you go: http://eel.is/c++draft/class.dtor#15. Do note is is pulled from the latest draft. – NathanOliver May 27 '16 at 13:25
  • @NathanOliver: good point (answering original question), and thanks for the reference. Hm, I must agree this sounds much like *…is invoke (no matter who or what invoked it)*, but then the object would no longer exist, and accessing things of non-existing objects *should* not be UB, right? – Marcus Müller May 27 '16 at 13:29
  • @MarcusMüller Why would accessing something that does not exist not be UB? It would be like using `int * foo; std::cout << *foo;`. What `foo` points to does not exist and this is UB. Trying to use the object after it is destroyed is UB. – NathanOliver May 27 '16 at 13:30
  • @NathanOliver: oh, true. – Marcus Müller May 27 '16 at 13:34