我阅读了以下内容
无法正常处理C ++构造函数中的错误 有理由避免构造者做什么比什么都没有,并使用 而是初始化函数。而C ++例外则不是 优雅的方式来处理错误,尤其是在构造函数中。如果你的 成员对象构造函数抛出异常,并且您想要捕获 它在你的构造函数中,通常丑陋的冒号语法得到很多 丑陋。
我想知道为什么构造函数不能优雅地处理错误?构造函数仍然可以支持try-catch,那么为什么构造函数不能优雅地处理错误呢?
答案 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
...
}
};
成员函数来检查文件是否在构造函数中成功打开(而不是让文件打开失败时构造函数抛出异常)。
这只是个人设计偏好的问题。