0

Why this code not call CloseHandles in class destructor?
In my code test I call '((MyClass*)pThis)->CloseHandles();' explicitly, but variable m_bFinished have wrong value. Why ?

#include <windows.h>
#include <exception>

class MyClass
{
public:

    explicit MyClass( void **pThis)
    {
        *pThis = this;
        m_bFinished = false;

        //code open handle here

        //an error occurs
        throw new std::exception("Exception thrown!");
    }

    ~MyClass()
    {
        if ( ! m_bFinished ) CloseHandles();
    }

    void CloseHandles()
    {
        if ( m_bFinished ) return;

        //close handles here.

        m_bFinished = true;
    }

private:
    bool m_bFinished;
};

int main(int argc, char* argv[])
{
    MyClass * pMyClass;
    void * pThis = NULL;

    try
    {
        pMyClass = new MyClass(&pThis);
    }
    catch(std::exception * e)
    {
        //delete pThis;

        if ( pThis )
        {
            ((MyClass*)pThis)->CloseHandles();
        }
    }

    return 0;
}

1 Answer 1

3

Because the destructor of a class doesnt' run when its constructor throws - the object hasn't been fully initialized yet.

Also, you're not actually throwing std::exception, but a pointer to it:

// dynamically allocates std::exception and throws a pointer to it
throw new std::exception("Exception thrown!");

EDIT: I noticed that you're catching a pointer, too, so that's not the problem. But, there's no constructor of std::exception that takes a string literal, so I wonder how your code even compiles.

In any case, if a constructor can possibly throw after a raw resource has been allocated, you have a potential leak.

You need to wrap the resource in class that manages it - a smart pointer perhaps or a similar RAII wrapper. And use member initializer lists!

Another option is constructor delegation (new in C++11). An object is considered fully constructed when any of its constructors finishes execution. This means that if an exception is thrown from a constructor that delegated to another constructor (where you'd do the acquisition of handles), the destructor will be called.

To illustrate with some code:

struct Handle {
    Handle() : handle(new int()) {}
    ~Handle() { delete handle; }
    int* handle;
};

class MyClass {
    Handle h;
    MyFlass() : h() // handle initialized here
    {
       /**** code that may throw ****/
       // this will properly close handles because
       // the destructors of already initialized
       // members (like h) will be called
    }
    ~MyClass() { /* not called if constructor throws */ }
};

And an example of constructor delegation:

#include <iostream>

class MyClass {
private:
    int* handle;
    MyClass(int)  // dummy parameter just for overloading
        : handle(new int()) { /* better not throw from here */ }
public:
    MyClass() : MyClass(0) // handle initialized here
    {
       /**** code that may throw ****/
       throw 42;
    }
    ~MyClass() { delete handle; std::cout << "dtor!"; }
};

int main()
{
    try { MyClass m; } catch (int) {};
}

Output is dtor!.

Sign up to request clarification or add additional context in comments.

4 Comments

But throwing 'throw std::exception("Exception thrown!")' and catching with 'catch(std::exception e)' the CloseHandles() still does not run.
As I said, a class' destructor does not run if its constructor throws.
In my code I call '((MyClass*)pThis)->CloseHandles();' explicitly, but variable m_bFinished have wrong value. Why ?
Not sure, what is the value supposed to be? As I said, the code doesn't compile and I can't try it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.