【问题标题】:Explicit call to destructor before longjmp/croak在 longjmp/croak 之前显式调用析构函数
【发布时间】:2013-03-28 16:30:25
【问题描述】:

我正在为 C++ 库编写一个 PERL XS 接口。当库抛出异常时,我需要调用croak

直接在异常处理程序中执行此操作会错过对已捕获异常的析构函数的调用,正如 longjmp 调用所期望的那样。这很重要,因为异常包含不会被释放的字符串成员。

显而易见的解决方案是在 catch 块之后执行croak,如果捕获到异常,如下所示:

bool do_croak = false;
try {
    throw MyException();
} catch (MyException &e) {
    do_croak = true;
}
if (do_croak)
    croak(NULL);

但我想知道:在longjmp 之前显式调用捕获的异常的析构函数就足够了吗?像这样:

try {
    throw MyException();
} catch (MyException &e) {
    e.~MyException();
    croak(NULL);
}

【问题讨论】:

    标签: c++ perl setjmp


    【解决方案1】:

    在 C++ 程序中安全地使用longjmp 几乎是不可能的。具体来说:

    C++11 18.10/4:如果将setjmplongjmp 替换为catchthrow,则setjmp/longjmp 调用对将调用任何重要的析构函数任何自动对象。

    在这种情况下,从croak 抛出异常将调用e 的析构函数,因此从那里调用longjmp 会产生未定义的行为。自己调用析构函数只会使行为更不明确。

    【讨论】:

    • 嗯。但是我提到的“显而易见的方法”(请参阅​​更新问题中的新代码)应该是理智的,假设只有 POD 不在捕获范围内? (我使用的是 C++98/03)
    • @Irfy:我不会将未定义的行为称为“理智”。如果您的意思是大多数编译器很可能最终会正确销毁e,尽管行为未定义,那么您可能是对的;但在我看来,依赖未定义的行为是一个非常糟糕的主意。
    • 也许你误解了我的意思。我的意思是在try-catch之后发生呱呱的方法。用 catch 替换 croak 不会导致任何析构函数运行,因为此时 e 已经被销毁。或者你是否也看到了未定义的行为?
    • @Irfy:抱歉,我没有注意到问题的变化。这确实是定义明确的只要你满足你不跳出任何非平凡析构函数的范围的要求。当然,这仍然很危险,因为没有办法强制执行该要求。
    • 很好。然后我会坚持我原来的方法。
    猜你喜欢
    • 2021-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-03
    • 2018-01-02
    相关资源
    最近更新 更多