为什么构造函数不能优雅地处理错误?

时间:2014-03-14 17:00:55

标签: c++ exception-handling

我阅读了以下内容

  

无法正常处理C ++构造函数中的错误   有理由避免构造者做什么比什么都没有,并使用   而是初始化函数。而C ++例外则不是   优雅的方式来处理错误,尤其是在构造函数中。如果你的   成员对象构造函数抛出异常,并且您想要捕获   它在你的构造函数中,通常丑陋的冒号语法得到很多   丑陋。

我想知道为什么构造函数不能优雅地处理错误?构造函数仍然可以支持try-catch,那么为什么构造函数不能优雅地处理错误呢?

2 个答案:

答案 0 :(得分:12)

  

我想知道为什么构造函数不能优雅地处理错误?

如果初始化失败,他们可以抛出异常。

这比将对象置于半活状态的建议更加“优雅”,以便稍后通过调用函数进行适当的初始化。正确使用 [1] ,异常保证对象完全初始化或不存在。

这个建议可能来自那些不赞成使用例外报告错误情况的人;在这种情况下,C ++确实成为一种极其笨拙的语言,没有方便的方式来表达初始化失败。幸运的是,在大多数C ++程序员中使用异常是惯用的,所以通常没有必要注意这种废话。

[1]具体来说,与RAII一起使用,以避免需要“在构造函数中捕获它”或除错误处理程序本身之外的任何地方。

答案 1 :(得分:6)

我认为"优雅地处理错误" 是主观的......

无论如何,作者可能正在考虑这样的事情:

class X
{
private:
   int * v1; // a vector of int's, dynamically allocated
   int * v2; // another vector of int's, dynamically allocated

public:
    X() 
    {
        v1 = new int[...];
        .... do something

        v2 = new int[...];
        ... If this throws, then v1 is leaked, since destructor is not called for X

        ...
    }
};

实际上,我认为如果你正确使用RAII和RAII构建块,就没有问题,构造函数可以优雅地处理错误(对于某些含义"优雅" )。

在上面的示例中,如果使用像<{1}}这样的 RAII 构建块替换原始动态分配的数组,则没有问题,因为如果在数据成员上调用析构函数,则类std::vector的构造函数中抛出异常(即使未调用X的析构函数):

X

无论如何,有些情况下你不想让构造函数抛出,例如一个文件类,您可以在其中使用class X { private: std::vector<int> v1; std::vector<int> v2; public: X() { v1.resize(...); .... do something v2.resize(...); // If this throws, then v1 is NOT leaked, // since the destructor is called for v1 data member ... } }; 成员函数来检查文件是否在构造函数中成功打开(而不是让文件打开失败时构造函数抛出异常)。
这只是个人设计偏好的问题。