C++ 在类构造函数上发生异常后清理数据

C++ 在类构造函数上发生异常后清理数据,c++,exception,constructor-exception,C++,Exception,Constructor Exception,为什么此代码不在类析构函数中调用CloseHandles? 在我的代码测试中,我调用“((MyClass*)pThis)->CloseHandles();”显式地,但变量m_bFinished的值错误。为什么? #include <windows.h> #include <exception> class MyClass { public: explicit MyClass( void **pThis) { *pThis = this;

为什么此代码不在类析构函数中调用CloseHandles?
在我的代码测试中,我调用“((MyClass*)pThis)->CloseHandles();”显式地,但变量m_bFinished的值错误。为什么?

#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; } #包括 #包括 类MyClass { 公众: 显式MyClass(void**p此) { *pThis=这个; m_bFinished=假; //代码在这里打开句柄 //发生错误 抛出新的std::异常(“抛出异常!”); } ~MyClass() { 如果(!m_bFinished)CloseHandles(); } void CloseHandles() { 如果(m_b完成)返回; //把把手关上。 m_bFinished=真; } 私人: 布尔姆·布菲完成; }; int main(int argc,char*argv[]) { MyClass*pMyClass; void*pThis=NULL; 尝试 { pMyClass=新的MyClass(&pThis); } 捕获(标准::异常*e) { //删除此项; 如果(pThis) { ((MyClass*)pThis)->CloseHandles(); } } 返回0; }
因为类的析构函数在构造函数抛出时不运行-对象还没有完全初始化

另外,您实际上并没有抛出
std::exception
,而是一个指向它的指针:

// dynamically allocates std::exception and throws a pointer to it
throw new std::exception("Exception thrown!");
编辑:我注意到你也在捕捉指针,所以这不是问题所在。但是,
std::exception
的构造函数没有接受字符串文本,所以我想知道您的代码是如何编译的

在任何情况下,如果构造函数可能在分配原始资源后抛出,则可能存在泄漏

您需要将资源包装在管理它的类中—可能是智能指针或类似的包装器。使用

另一个选项是构造函数委托(C++11中新增)。当对象的任何构造函数完成执行时,对象被认为是完全构造的。这意味着,如果从委托给另一个构造函数的构造函数(您将在其中获取句柄)引发异常,将调用析构函数

用一些代码来说明:

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 */ }
};
还有一个构造函数委托的示例:

#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) {};
}
#包括
类MyClass{
私人:
int*句柄;
MyClass(int)//仅用于重载的伪参数
:handle(new int()){/*最好不要从这里抛出*/}
公众:
MyClass():MyClass(0)//在此处初始化句柄
{
/****可能引发****/
投掷42枚;
}

~MyClass(){delete handle;std::cout因为类的析构函数在构造函数抛出时不会运行-对象尚未完全初始化

另外,您实际上并没有抛出
std::exception
,而是一个指向它的指针:

// dynamically allocates std::exception and throws a pointer to it
throw new std::exception("Exception thrown!");
编辑:我注意到您也在捕获指针,所以这不是问题所在。但是,没有采用字符串文字的
std::exception
构造函数,所以我想知道您的代码是如何编译的

在任何情况下,如果构造函数可能在分配原始资源后抛出,则可能存在泄漏

您需要将资源包装在管理它的类中—可能是一个智能指针或类似的包装器。然后使用

另一个选项是构造函数委托(C++11中新增)。当对象的任何构造函数完成执行时,该对象被视为完全构造。这意味着,如果从委托给另一个构造函数的构造函数(您将在其中获取句柄)引发异常,将调用析构函数

用一些代码来说明:

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 */ }
};
还有一个构造函数委托的示例:

#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) {};
}
#包括
类MyClass{
私人:
int*句柄;
MyClass(int)//仅用于重载的伪参数
:handle(new int()){/*最好不要从这里抛出*/}
公众:
MyClass():MyClass(0)//在此处初始化句柄
{
/****可能引发****/
投掷42枚;
}

~MyClass(){delete handle;std::cout因为类的析构函数在构造函数抛出时不会运行-对象尚未完全初始化

另外,您实际上并没有抛出
std::exception
,而是一个指向它的指针:

// dynamically allocates std::exception and throws a pointer to it
throw new std::exception("Exception thrown!");
编辑:我注意到您也在捕获指针,所以这不是问题所在。但是,没有采用字符串文字的
std::exception
构造函数,所以我想知道您的代码是如何编译的

在任何情况下,如果构造函数可能在分配原始资源后抛出,则可能存在泄漏

您需要将资源包装在管理它的类中—可能是一个智能指针或类似的包装器。然后使用

另一个选项是构造函数委托(C++11中新增)。当对象的任何构造函数完成执行时,该对象被视为完全构造。这意味着,如果从委托给另一个构造函数的构造函数(您将在其中获取句柄)引发异常,将调用析构函数

用一些代码来说明:

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 */ }
};
还有一个构造函数委托的示例:

#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) {};
}
#包括
类MyClass{
私人:
int*句柄;
MyClass(int)//仅用于重载的伪参数
:handle(new int()){/*最好不要从这里抛出*/}
公众:
MyClass():MyClass(0)//在此处初始化句柄
{
/****可能引发****/
投掷42枚;
}

~MyClass(){delete handle;std::cout因为类的析构函数在构造函数抛出时不会运行-对象尚未完全初始化

另外,您实际上并没有抛出
std::exception
,而是一个指向它的指针:

// dynamically allocates std::exception and throws a pointer to it
throw new std::exception("Exception thrown!");
编辑:我注意到您也在捕获指针,所以这不是问题所在。但是,没有采用字符串文字的
std::exception
构造函数,所以我想知道您的代码是如何编译的

在任何情况下,如果构造函数可能在分配原始资源后抛出,则可能存在泄漏

您需要将资源包装在clas中