当前位置: 首页 > 知识库问答 >
问题:

在类构造函数上清除异常后的数据

梁承恩
2023-03-14

为什么这段代码不在类析构函数中调用CloseHandles
在我的代码测试中,我调用“((MyClass*)pThis)-

#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个答案

曾德水
2023-03-14

因为类的析构函数在构造函数抛出时不会运行,所以对象还没有完全初始化。

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

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

编辑:我注意到你也在捕捉指针,所以这不是问题所在。但是,std::exception的构造函数不接受字符串文本,所以我想知道你的代码是如何编译的。

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

您需要将资源封装在管理它的类中——可能是一个智能指针或类似的RAII包装器。并使用成员初始值设定项列表!

另一个选项是构造函数委托(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) {};
}

输出是dtor!

 类似资料:
  • 问题内容: 在C ++中,对象的生命周期从构造函数成功完成时开始。在构造函数内部,该对象尚不存在。 问:从构造函数发出异常是什么意思? 答:这意味着构造已失败,该物体从未存在,其寿命从未开始。[ 来源 ] 我的问题是:Java是否同样适用?例如,如果我移交给另一个对象,然后构造函数失败,会发生什么情况? 这个定义明确吗?现在是否有对非对象的引用? 问题答案: 该对象存在,但未正确初始化。 每当构造

  • 首先要处理前面已经提到但还没有完全解决的问题。构造函数中发现错误时会发生什么情况? 例如,String 构造函数在 new 失败和无法取得保持 String 的内部表示所需空间时如何响应?问题是构造函数无法返回数值,如何让外部知道对象没有顺利构造呢,一种方案是返回没有正确构造的对象,希望对象使用者通过相应测试确定该对象是不能使用的对象。另一种方案是在构造函数之外设置一些变量。抛出的异常向外部传递失

  • 问题内容: 目前,我正在尝试在类构造函数中使用。这样一来,我就可以为正在从事的Electron项目获取自定义标签。 但是,目前该项目无法正常工作,并出现以下错误: 有没有办法避免这种情况,以便我可以在其中使用异步/等待?而不需要回调或.then()? 问题答案: 这 永远 行不通。 该关键字允许在标记为函数中使用,但它也是功能转换成一个承诺发生器。因此,标有的函数将返回承诺。另一方面,构造函数返回

  • 问题内容: 我如何最好地处理以下情况? 我有一个构造函数,需要一些时间才能完成。 我看到了三个选项,每个选项似乎都与众不同。 一种 ,向构造函数添加回调。 第二 ,使用EventEmitter发出“已加载”事件。 或三 ,阻止构造函数。 但我以前从未见过任何完成的事情。 我还有什么其他选择? 问题答案: 鉴于有必要避免在Node中进行阻塞,事件或回调的使用并不奇怪(1)。 稍加修改为2,即可将其与

  • 有没有人可以帮助我理解为什么在向一个接受两个参数的类添加了一个新的构造函数之后,项目编译了,但是我的测试现在不能创建这个类的新实例? 我有一个例外: java.lang.nosuchmethoderror:pidac.workflow.testclass。(lcom/pidac/infrastructure/core/service/crudservice;lcom/pidac/infrastru