C ++构造函数初始化列表抛出异常

时间:2013-07-10 06:42:41

标签: c++ list exception constructor initializer

我遇到以下代码问题。正如我们所看到的,我已经处理了A的构造函数在C的构造函数中抛出的异常,为什么我还要在main函数中再次捕获并处理异常?

#include <iostream>

class WException : public std::exception
{
public:
    WException( const char* info ) : std::exception(info){}
};

class A
{
public:
    A( int a ) : a(a) 
    {
        std::cout << "A's constructor run." << std::endl;
        throw WException("A constructor throw exception.");
    }

private:
    int a;
};

class B
{
public:
    B( int b ) : b(b) 
    {
        std::cout << "B's constructor body run." << std::endl;
        throw WException("B constructor throw exception");
    }

private:
    int b;
};

class C : public A, public B
{
public:
    C( int a, int b ) try : A(a), B(b)
    {
        std::cout << "C's constructor run." << std::endl;
    }
    catch( const WException& e )
    {
        std::cerr << "In C's constructor" << e.what() << std::endl;
    }
};

int main( int argc, char* argv[] )
{
    try
    {
        C c( 10, 100 );
    }
    catch( const WException& e )
    {
        std::cerr << "In the main: " << e.what() << std::endl;
    }   

    return 0;
}

1 个答案:

答案 0 :(得分:16)

您实际上无法在构造函数中捕获异常。你可以处理它,但你必须重新抛出它或另一个例外。原因是对象完整性和对象生命周期:

如果a的构造被抛出,c的一部分尚未初始化且完全丢失 - a的生命周期永远不会开始。 a不是C的可选部分,否则它必须是指针或std::optional(因为C ++ 14 - boost::optional之前)。

那么,如果无法构建其中一个重要部分,您如何组装C?你不能。 c永远不会作为完整对象开始存在,因此您无法正常退出构造函数。这就是为什么如果构件对象的构造失败,整个对象的构造必须失败,即必须抛出异常。

如果你没有在C::C的catch块中抛出异常,编译器会为你做这个。

C ++标准,§15.3,15

  

如果控制到达构造函数或析构函数的function-try-block的处理程序的末尾,则重新抛出当前处理的异常。

有关该主题的更广泛的处理,请参阅http://www.gotw.ca/gotw/066.htm