在C++中从错误条件退出构造函数的最佳技术是什么

Jac*_*ble 20 c++ constructor

在C++中从错误条件退出构造函数的最佳技术是什么?特别是,打开文件时出错.

谢谢你的回复.我正在抛出异常.这是代码(不知道它是否是最好的方法,但它很简单)

// Test to see if file is now open; die otherwise 
if ( !file.is_open() ) {
    cerr << "Failed to open file: " << m_filename << endl;
    throw ("Failed to open file");
}   
Run Code Online (Sandbox Code Playgroud)

有人认为我喜欢C++,你不必在方法声明上声明抛出的异常.

Bri*_*ndy 27

最好的建议可能是parashift所说的.但请阅读下面的注意事项.

见parashift FAQ 17.2

[17.2]如何处理失败的构造函数?

抛出一个例外.

构造函数没有返回类型,因此无法使用返回代码.因此,表示构造函数失败的最佳方法是抛出异常.如果您没有使用异常的选项,那么"最不好"的解决方法是通过设置内部状态位将对象置于"僵尸"状态,这样对象的行为有点像死了,即使它是技术上还活着.

"僵尸"对象的想法有很多不足之处.你需要添加一个查询("督察")成员函数来检查这个"僵尸"位,这样你班级的用户就可以知道他们的对象是否真的存活,或者它是一个僵尸(即一个"活死人"对象) ,几乎每个你构建一个对象的地方(包括在一个更大的对象或一个对象数组中),你需要通过if语句检查那个状态标志.你还需要为你的其他成员函数添加一个if:如果对象是一个僵尸,那么做一个no-op或者更令人讨厌的东西.

在实践中,"僵尸"的东西变得非常难看.当然你应该比zombie对象更喜欢异常,但是如果你没有使用异常的选项,那么僵尸对象可能是"最不好"的选择.


在构造函数中抛出异常时要小心谨慎:

但要非常小心,因为如果在构造函数中抛出异常,则不会调用类的析构函数.因此,在抛出异常之前,需要注意破坏已经构造的对象.一般来说,相同的警告适用于异常处理,但在处理构造函数时,它可能稍微不那么明显.

class B
{
public:
    B()
    {

    }

    virtual ~B()
    {
        //called after D's constructor's exception is called
    }
};

class D : public B
{
public:
    D()
    {
        p = new char[1024];
        throw std::exception("test");
    }

    ~D()
    {
      delete[] p;
      //never called, so p causes a memory leak
    }

    char *p;
};

int main(int argc, char **argv)
{

    B *p;
    try
    {
        p = new D();
    }
    catch(...)
    {

    }


    return 0;
}
Run Code Online (Sandbox Code Playgroud)

使用CreateInstance方法的受保护/私有构造函数:

另一种方法是使您的构造函数成为私有或受保护的,并创建一个可以返回错误的CreateInstance方法.


Ada*_*eld 7

您可以像其他人提到的那样抛出异常,或者您也可以重构代码,以便构造函数不会失败.例如,如果您正在处理禁用或禁止例外的项目,那么后者是您的最佳选择.

要创建一个不会失败的构造函数,重构可能会失败的代码init(),并让构造函数尽可能少地工作,然后要求所有类的用户init()在构造后立即调用.如果init()失败,您可以返回错误代码.请务必在课程文档中记录这一点!

当然,这有点危险,因为程序员可能会忘记打电话init().编译器无法强制执行此操作,因此请谨慎操作,并尝试在init()未调用时使代码快速失败.

  • @Adam Rosenfield:+1我同意,空构造函数不能失败,甚至在调用构造函数之前都会抛出内存异常。 (2认同)

小智 5

通常,您应该抛出异常。另一种方法是拥有一些构造不正确的对象,用户必须以某种方式对其进行测试,而他们将不可避免地无法做到这一点。