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

Why can't constructors gracefully handle errors?

本文关键字:处理 错误 构造函数 不能 为什么      更新时间:2023-10-16

我读了下面的

无法优雅地处理c++构造函数中的错误就是其中之一这是避免构造函数的一个很好的理由而是初始化函数。c++异常不是处理错误的优雅方式,特别是在构造函数中。如果你的成员对象构造函数抛出异常,您希望捕获如果在构造函数中,通常丑陋的冒号语法会变得更加复杂丑陋。

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

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

可以,当初始化失败时抛出异常。

这比让对象处于半活动状态,以便稍后调用函数进行适当初始化的建议要"优雅"得多。正确使用[1],异常保证对象要么完全初始化,要么不存在。

这个建议可能来自不赞成使用异常来报告错误条件的人;在这种情况下,c++确实变成了一种极其笨拙的语言,没有方便的方法来表示初始化失败。幸运的是,异常的使用在大多数c++程序员中是惯用的,所以通常不需要注意这类废话。

[1]特别地,与RAII结合使用,以避免需要"在构造函数中捕获它"或除了错误处理程序本身之外的任何地方。

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

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

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构建块,就不会有问题,并且构造函数可以优雅地处理错误(对于"优雅"的某些含义)。

在上面的例子中,如果你用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
        ...
    }
};

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