0

I just had an interview question, the interviewer asked

How to tell the destructor is not called when it should have be called?

And what will you do if the destructor is not called?

To be honest, I don't know the answer. My guess is that putting the destructor inside a try catch block, but I have never seen people doing that. Is there a better solution?

Allanqunzi
  • 3,230
  • 1
  • 26
  • 58
  • 5
    The question is pretty vague. Can we get some context? – Kevin Dec 11 '15 at 20:45
  • 1
    Was there any context given? Do they mean “not called *yet*”, “not called at program exit”, “*maybe* not called (on some execution paths)” or maybe something different? – 5gon12eder Dec 11 '15 at 20:45
  • @Kevin, the interviewer didn't give any context. – Allanqunzi Dec 11 '15 at 20:46
  • 1
    AFAIK the only time a destructor is not called is when you have a pointer created with `new`/`new[]` and you do not `delete`/`delete[]` it. – NathanOliver Dec 11 '15 at 20:46
  • For second part I agree with @NathanOliver for the first part I would use a `printf` :P. – 101010 Dec 11 '15 at 20:47
  • @NathanOliver, There are other cases such as aborting execution. – chris Dec 11 '15 at 20:47
  • @chris Yes there is that. I was only thinking of during the course of the programming running. in the case of `abort` the program ends so you have a bigger issue then the destructors not being called. – NathanOliver Dec 11 '15 at 20:48
  • 4
    Perhaps the point of the question in the interview is to get the candidate to ask for clarification and to start a discussion?! – Ed Heal Dec 11 '15 at 20:49
  • I guess English is not your native tongue (that's not a criticism, just an observation - I work in a foreign language and it's ***** hard). Do you mean "How can you tell if the destructor of an object has not been called?". – Martin Bonner supports Monica Dec 11 '15 at 20:50
  • @MartinBonner, thank you. Yes, and add "when it should have been called" to the end of your sentence. – Allanqunzi Dec 11 '15 at 20:55
  • [disable destructors for static variables](http://stackoverflow.com/questions/27671498/c-disable-destructors-for-static-variables) one of the examples – sav_a Dec 11 '15 at 20:57
  • 1
    Maybe the interviewer was fishing for a discussion about static members? A static int member that you increment upon construction and decrement upon destruction is a common way to count instances of a class, so you could use that counter to detect whether the destructor has been called as expected. For cleanup, I guess you could also store and maintain a static vector of pointers to instances of a class instead of counter, but I can't imagine how you'd differentiate the legitimate ones from the leaked instances unless you want to go nuclear and delete every instance of the class at some point. – Mark Waterman Dec 11 '15 at 20:58
  • @EdHeal, oh, if that's the case I would think I was trapped. But the pace of the interview was pretty fast, the interviewer tried to ask as many questions as possible and expected me to give the answer right away. – Allanqunzi Dec 11 '15 at 20:59
  • Probably not. Did you give quick and short answers? Perhaps due to nerves – Ed Heal Dec 11 '15 at 21:00
  • @EdHeal, this question looked pretty weird to me, I never thought that a destructor can not be called when it should be. I said something about using the `try catch` block, but the interviewer said no. You're right I was a little nervous during the process. – Allanqunzi Dec 11 '15 at 21:03
  • 1
    @Allanqunzi - Next time in an interview do the following. Technical questions you are not expected to answer them quickly with short answers. Ask for clarification. Take your time. Ask to write stuff down (perhaps use a white board. In addition ask them questions. In many cases they are not particularly interested if you get the question completely correct and are more interested in how you think. – Ed Heal Dec 11 '15 at 21:10
  • @Allanqunzi: "I never thought that a destructor can not be called when it should be." It rather depends on what "when it should be" means. The standard defines the basic level of "when it should be". Namely, when the object's lifetime ends. The interviewer clearly has a different definition, since by the standard, it is *impossible* for a destructor to not be called when the standard says that it will. Unless your compiler is *broken*. – Nicol Bolas Dec 11 '15 at 21:14
  • @EdHeal, thank you very much for the advice. – Allanqunzi Dec 11 '15 at 21:16
  • @Allanqunzi - They are not out to get you. Try to think that an interview is a two way street to have a constructive conversation. They want to find out about you and you should want to find out about them. It is bit like a first date without the possibility of having sex – Ed Heal Dec 11 '15 at 21:19
  • @Nicol Bolas: Well (by definition), according to the standard the destructor will be called when the standard says it will. However, back in the real world, destructors are often not called when you naively think they should have been. I listed a few examples in my answer. – Martin Bonner supports Monica Dec 11 '15 at 21:19
  • @MartinBonner: Like I said: the answer depends on what "when it should be" means. – Nicol Bolas Dec 11 '15 at 21:21

6 Answers6

8

There are a number of ways that the destructor of an object can fail to be called:

  • call abort or _exit (even exit will leave stack variables undestructed).
  • have the constructor thrown an exception. (Technically, if the constructor threw, the object never started to exist, so there wasn't an object to have its destructor called).
  • invoke undefined behaviour (at which point the C++ standard allows anything to happen). Calling deleteon an array allocated with new [] is one way of invoking undefined behaviour, and one common behaviour is to call the destructor of the first object only (leaving second and subsequent undestructed) - but it's still undefined behaviour.
  • Another way to invoke undefined behaviour is a way which is quite likely to leave a destructor uncalled is to have a pointer-to-base which actually points to a derived object, and call delete on the pointer-to-base. If the base class doesn't have a virtual destructor, you have undefined behaviour.
  • you have not yet called delete on a pointer allocated with new (this is particularly problemmatic if you have a memory leak). (This is actually a particularly common case of "the destructor is not supposed to have been run yet").

If you are trying to debug a program and want to find out if the destructor is being invoked, then

  • set a break point and run under the debugger
  • printf or whatever logging framework you are using.
4

Here is another classic no-destruction:

#include <iostream>
#include <memory>

class Base
{
public:
    Base()
    {
        std::cout << "All your base, sucker!" << std::endl;
    }
    ~Base() <-- note lack of virtual
    {
        std::cout << "Base destroyed!" << std::endl;
    }
};

class Sub: public Base
{
public:
    Sub()
    {
        std::cout << "We all live in a Yellow Submarine..." << std::endl;
    }
    ~Sub()
    {
        std::cout << "Sub destroyed" << std::endl;
    }

};

int main()
{
    std::unique_ptr<Base> b(new Sub());
}

Output:

All your base, sucker!
We all live in a Yellow Submarine...
Base destroyed!

Because Base's destructor is not virtual, ~Base is called instead of ~Sub on destruction, and ~Base has no clue that Sub even exists and can't call ~Sub to finish clean-up.

user4581301
  • 33,082
  • 7
  • 33
  • 54
2

You can for example put a static bool in the class you want to test, set it true in the constructor and false in the destructor. When the destructor is not called, the bool will remain true. Or it can be a static int, increment in the constructor and decrement in the destructor (and check counts before and after the scope). This is one of simple methods to check for resource leaks. I was already using this technique in unit tests to easily check if the correct constructor has been called when a custom smart pointer went out of scope.

The destructor might not be called in many situations, usually as a result of programming error. For example:

  • deleting inherited class through a base class pointer without having virtual destructor (then only base destructor is called)
  • deleting pointer to forward declared class (this case is tricky, as only some of the compilers issue a warning)
  • forgetting to delete at all (memory leak)
  • initializing object by placement new and not calling the destructor manually (which is required for placement new)
  • mismatched array/non-array operators (allocating by new[] and deleting by regular delete - if it does not crash it only calls destructor of the first item)
EmDroid
  • 5,918
  • 18
  • 18
0

I do not know what Interviewer wanted to ask you as context is not clear but below points may be helpful

For a object on stack - Destructor is called as the object go out of scope.

For a object created on heap - for each object created by new , a delete will call the destructor. In case the program terminates before delete the destructor may not be called, In such proper handling should be done ( I would recommend using smart pointers to avoid such cases)

Ajay
  • 775
  • 5
  • 19
0

Here is an example where the destructor is not called:

#include <iostream>

class A {
  public:
     ~A() { std::cout << "Destructor called" << std::endl;}
};

int main()
{
   A *a = new A;
   return 0;
}

There are plenty of other examples. Like casting, static, ...

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
Ed Heal
  • 59,252
  • 17
  • 87
  • 127
0

It's not easy to detect a "negative event": that something didn't happen.

Instead what we test for is some event which happens unconditionally, and always after the interesting event that we are trying to detect (when that event does happen). When that other even happens, we then know that we are past the point in time when the interesting happen should have happened (if it happened at all). At that point, we have justification in looking for some positive evidence which determines whether the interesting event happened or not.

For instance, we can have the destructor set some kind of flag, or invoke some callback function or whatever. We also know that a C++ program executes statements in sequence. So suppose we don't know whether a given destructor was called during the execution of statement S1 in S1 ; S2. We simply arrange for the gathering of evidence, prior to executing S1, and then in or after S2, we look for that evidence (is the flag set, was the callback invoked, ...)

If this is just during debugging, then use your debugger or code coverage tools!

If you're wondering "is this line of code executed while I run such and such", then put a debugger breakpoint on it..

Or run a code coverage tool and then analyze the results: it will tell you how many times the lines of your program were reached. Lines that weren't executed will be flagged as never reached (no coverage). Code coverage can accumulate the coverage info from multiple runs of the program; they can help you find code that is not being hit by your test cases.

Kaz
  • 55,781
  • 9
  • 100
  • 149