非虚拟析构函数 c++ 的异常

exception with non virtual destructor c++

当我们超出 catch 块作用域时,是否会调用异常析构函数? (以防我们不重新抛出它)

假设我有 class A,并且它的析构函数不是虚拟的。 B继承了A。 假设某个函数将 B class 的对象作为异常抛出, 它被捕获块捕获

catch(A& a){
...
}

如果在超出catch范围时调用异常析构函数, 在这种情况下,只有基础 class A 的析构函数会被调用?

玉米杆: 调用两个 class 析构函数的现场试验结果。

这与我的逻辑相矛盾。解释某人?

when we go out of catch block scope, does the exception destructor is called? (In case we don't rethrow it)

是:

[C++11: 15.1/4]: [..] The exception object is destroyed after either the last remaining active handler for the exception exits by any means other than rethrowing, or the last object of type std::exception_ptr (18.8.5) that refers to the exception object is destroyed, whichever is later. [..]


if the exception destructor should be called when go out of catch scope, in this case only the base class A's d'tor will be called?

No:

#include <iostream>

struct A
{
    A() { std::cout << "A()"; }
    A(const A&) { std::cout << "A(const A&)"; }
    A(A&&) { std::cout << "A(A&&)"; }
    ~A() { std::cout << "~A()"; }
};

struct B : A
{
    B() { std::cout << "B()"; }
    B(const B&) { std::cout << "B(const B&)"; }
    B(B&&) { std::cout << "B(B&&)"; }
    ~B() { std::cout << "~B()"; }
};

int main()
{
    try {
        throw B();
    }
    catch (A&) {
    }
}

// Output: A()B()~B()~A()

虽然我没有引用标准,但似乎抛出一个 B 并捕捉一个 A& 将导致 AB的析构函数被调用。 Live demo:

#include <iostream>

struct A
{
    ~A() { std::cout << "A::~A" << std::endl; }
};

struct B : public A
{
    ~B() { std::cout << "B::~B" << std::endl; }
};

void throwit()
{
    throw B{};
}

int main()
{
    std::cout << "beginning main scope" << std::endl;

    {
        std::cout << "beginning inner scope" << std::endl;

        try
        {
            std::cout << "calling throwit()" << std::endl;
            throwit();
        }
        catch (A& a)
        {
            std::cout << "caught exception" << std::endl;
        }

        std::cout << "ending inner scope" << std::endl;
    }

    std::cout << "ending main scope" << std::endl;
}

输出:

beginning main scope
beginning inner scope
calling throwit()
caught exception
B::~B
A::~A
ending inner scope
ending main scope

如您所见,两个析构函数都被调用了。额外的范围打印非常清楚地显示析构函数何时被调用(在 catch 块的末尾)。

好的,已经有人回答了你的第一个问题。我将专注于此:

if the exception destructor should be called when go out of catch scope, in this case only the base class A's d'tor will be called?

实现将始终正确销毁异常对象,无论它是如何捕获的。实现构造了异常对象,所以它知道如何销毁它。这与通过指针调用 delete 时不同,因为在那种情况下,此时关于对象的完整类型的信息不完整(它可能已在其他地方被 newed)除非存在虚拟析构函数。

如果不是这样,catch (...) 将永远无法工作。

只要标准说一个对象被销毁,就意味着调用了正确的最派生析构函数。

总是。

当你在没有虚拟析构函数的情况下多态删除一个对象,或者你终止(通过 delete 运算符或显式析构函数调用)一个不完整类型的对象并且适当的析构函数是非平凡的,标准不会说那个对象被摧毁了。它并没有说调用了 base class 析构函数。它说你有未定义的行为。