Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the destructor ignored in this code?

Tags:

People also ask

Why is my destructor not called?

The memory created using the operator new must be explicitly deallocated. Since the objects *pJ and *pK are never destroyed by the code, the desctructors are never called.

Why is my destructor being called C++?

Destructors are called when one of the following events occurs: A local (automatic) object with block scope goes out of scope. An object allocated using the new operator is explicitly deallocated using delete . The lifetime of a temporary object ends.

Do you have to call a destructor in C++?

No. You never need to explicitly call a destructor (except with placement new ). A class's destructor (whether or not you explicitly define one) automagically invokes the destructors for member objects. They are destroyed in the reverse order they appear within the declaration for the class.

How does a destructor work in C++?

A destructor is a member function that is invoked automatically when the object goes out of scope or is explicitly destroyed by a call to delete . A destructor has the same name as the class, preceded by a tilde ( ~ ). For example, the destructor for class String is declared: ~String() .


The following code demonstrates a weird problem I have in a Turbo C++ Explorer project. One of the three stack objects in D::D() is not destroyed after going out of scope.

This only happens if compiled in release mode, the auto_ptrs a_ and b_ are of different types and the exception thrown doesn't inherit from std::exception. It appears to work just fine in VC++ 2005 and C++ Builder 2009. I did install the BDS2006 Update 2, the hotfix rollup and hotfix 12.

Is it my code or the compiler? Do you know of a fix? Not being able to reliably use auto_ptr in a VCL project would be quite inconvenient.


#include <memory>
#include <stdexcept>
#include <iostream>

typedef std::exception my_error; // will work fine if replaced with line below
//class my_error : public std::exception {};

class A {};
class B {};

class C
{
public:
    C(int id) : id_(id) { std::cout << "C::C() " << id_ << std::endl; };
    ~C() { std::cout << "C::~C() " << id_ << std::endl; };
private:
    int id_;
};

class D
{
public:
    D()
    {
        C c1(1);
        C c2(2);
        C c3(3);

        throw my_error();
    };

private:
    std::auto_ptr<A> a_;
    std::auto_ptr<B> b_; // will work fine if replaced with line below
//  std::auto_ptr<A> b_;
//  std::auto_ptr<C> c_; // see expected output
};

#pragma argsused
int main(int argc, char* argv[])
{
    try
    {
        D d;
    }
    catch (...)
    {
        std::cout << "caught exception" << std::endl;
    }

    return 0;
}


Expected:

C::C() 1
C::C() 2
C::C() 3
C::~C() 3
C::~C() 2
C::~C() 1
caught exception


Got:

C::C() 1
C::C() 2
C::C() 3
C::~C() 2
C::~C() 1
caught exception


Got (with line '// std::auto_ptr<C> c_;' uncommented):

C::C() 1
C::C() 2
C::C() 3
C::~C() 1
caught exception


Edit: Made suggested changes

Edit 2:
I just tested it with C++ Builder 2007 (11.0.2902.10471), which shows the same problem. The release configuration works as soon as I check the "Debug information" box in Project -> Options -> C++ Compiler -> Debugging. It surprises me that the executable gets smaller with "Debug information" enabled (down to 31.5 KB from 39.5 KB ).

Edit 3:
In Turbo C++ Explorer (C++ Builder 2006) (10.0.2288.42451) the release configuration works if I uncheck the "Inline function expansion (-vi)" box in Project -> Options -> C++ Compiler -> Debugging. Replacing the first line (#include <memory>) with the following code makes it work, too.

#pragma option push -vi-
#include <memory>
#pragma option pop