是否可以毫无例外地进行RAII?

时间:2015-10-23 11:10:50

标签: c++ raii

如果在构造对象时需要获取的资源可能失败,那么如果本地编码标准禁止例外,是否可以进行RAII?

如果是这样,在这种情况下处理资源获取失败的规范方式是什么?

2 个答案:

答案 0 :(得分:7)

我不会采用无效对象方法,因为我认为这是一个糟糕的设计。构造之后,对象必须处于建立不变量的状态(这是构造函数应该服务的唯一目的)。考虑实现strange_vector之类的类std::vector,但在调用strange_vector<int>(10, 0)之后,对象将处于不可用状态,因为分配失败。

相反,我会将构造函数声明为private并使用返回可选的工厂方法:

class file
{
public:
    ~file() {fclose(m_file);}

    static std::optional<file> open(std::string const& filename)
    {
        auto f = fopen(filename.c_str(), "r");
        if (f)
        {
            return std::make_optional<file>(f);
        }
        else
        {
            return std::nullopt;
        }
    }

private:
    file(FILE* file);
    FILE* m_file;
};

异常处理的最大好处之一是(除了解耦错误处理和普通代码路径之外),您不会意外地忽略它们。如果你想要,你可以创建一个类似于optional的类,当没有用有效对象初始化时,它会记录一条错误消息并终止你的程序(或任何其他合理的错误处理)。我认为有一个talk from A. Alexandrescu about systematic error handling,他实现了一个类Expected<T>,它包含类型T的值或异常。您可以使用此基础而不是异常添加您的错误处理。

std::optional尚未成为标准的一部分,但您可以轻松地将实现作为最近编译器,boost或其他库的一部分。

答案 1 :(得分:0)

您始终可以创建bool valid(void)方法。然后构造函数可以设置适当的条件,并且在您的代码中,您可以在构造之后检查这是否有效。

class foo
{
public:
    foo(const char *Filename)
    {
        mValid = false;

        if(fopen(Filename) == NULL)
           return;

        mValid = true;
    }

    bool valid(void) { return mValid; }

    private:
        bool mValid;
};

void myfunc(void)
{
    foo fl("myfile");
    if(!fl.valid())
    {
        printf("Error\n");
        return;
    }
}