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

Raj*_*war 5 c++ exception-handling

我读了以下内容

无法优雅地处理C++构造函数中的错误是避免构造函数不仅仅是什么的一个很好的理由,而是使用初始化函数.并且C++异常不是处理错误的优雅方式,尤其是在构造函数中.如果您的成员对象构造函数抛出异常,并且您想在构造函数中捕获它,那么通常难看的冒号语法会变得更加丑陋.

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

Mik*_*our 12

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

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

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

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

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


Mr.*_*C64 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

        ...
    }
};
Run Code Online (Sandbox Code Playgroud)

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

在上面的示例中,如果使用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

        ...
    }
};
Run Code Online (Sandbox Code Playgroud)

无论如何,有些情况下你只是不想要构造函数抛出,例如一个文件类,你可以在其中有一个IsOpen()成员函数来检查文件是否在构造函数中成功打开(而不是让构造函数抛出一个文件打开失败时的异常).
这只是个人设计偏好的问题.