C++核心准则C.42:如果构造函数不能生成合法对象就抛出异常

 

C.42: If a constructor cannot construct a valid object, throw an exception

C.42:如果构造函数不能生成合法对象就抛出异常

Reason(原因)

Leaving behind an invalid object is asking for trouble.

将无效对象留给后续处理就等于是自找麻烦。

Example(示例)

class X2 {
    FILE* f;
    // ...
public:
    X2(const string& name)
        :f{fopen(name.c_str(), "r")}
    {
        if (!f) throw runtime_error{"could not open" + name};
        // ...
    }

    void read();      // read from f
    // ...
};

void f()
{
    X2 file {"Zeno"}; // throws if file isn't open
    file.read();      // fine
    // ...
}

Example, bad(反面示例)

class X3 {     // bad: the constructor leaves a non-valid object behind
    FILE* f;   // call is_valid() before any other function
    bool valid;
    // ...
public:
    X3(const string& name)
        :f{fopen(name.c_str(), "r")}, valid{false}
    {
        if (f) valid = true;
        // ...
    }

    bool is_valid() { return valid; }
    void read();   // read from f
    // ...
};

void f()
{
    X3 file {"Heraclides"};
    file.read();   // crash or bad read!
    // ...
    if (file.is_valid()) {
        file.read();
        // ...
    }
    else {
        // ... handle error ...
    }
    // ...
}

Note(注意)

For a variable definition (e.g., on the stack or as a member of another object) there is no explicit function call from which an error code could be returned. Leaving behind an invalid object and relying  on users to consistently check an is_valid() function before use is tedious, error-prone, and inefficient.

变量定义(例如在堆栈或者作为其他对象的成员)不存在用于返回错误代码的明确的函数调用。留给后续处理一个无效对象并且依靠用户在使用之前总是通过一个is_valid()函数进行检查的做法是乏味的,易错和低效的。

Exception(例外)

There are domains, such as some hard-real-time systems (think airplane controls) where (without additional tool support) exception handling is not sufficiently predictable from a timing perspective. There the is_valid() technique must be used. In such cases, check is_valid() consistently and immediately to simulate RAII.

有些领域,例如硬实时系统(例如飞机控制),它们(如果没有另外的工具支持)从时机的方面来讲异常处理不是充分可预测的。这里必须采用is_valid()技术。在这样的情况下,需要自始至终地检查is_valid()并且立刻模仿RAII的行为。

1.RAII是Resource Acquisition Is Initialization(wiki上面翻译成 “资源获取就是初始化”)的简称,是C++语言的一种管理资源、避免泄漏的惯用法。链接:https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rr-raii

2.硬实时系统无法终端程序执行,因此无法抛出异常。

Alternative(其他选项)

If you feel tempted to use some "post-constructor initialization" or "two-stage initialization" idiom, try not to do that. If you really have to, look at factory functions.

如果想要使用前置条件初始化或者两阶段初始化,不要那么做。如果你真的必须那样做,考虑工厂函数。

工厂函数:https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rc-factory

Note(注意)

One reason people have used init() functions rather than doing the initialization work in a constructor has been to avoid code replication.Delegating constructors and default member initialization do that better. Another reason has been to delay initialization until an object is needed; the solution to that is often not to declare a variable until it can be properly initialized。pa

人们使用init()函数而不是在构造函数内部进行初始化处理是希望避免代码重复。委托构造函数和默认成员初始化可以做地更好。另外一个原始是希望将对象的初始化延迟到它被使用之前;解决方法通常是等到变量可以被正确的初始化时在声明它。

委托构造函数:https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rc-delegating

Enforcement(实施建议)

???

原文链接

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#c42-if-a-constructor-cannot-construct-a-valid-object-throw-an-exception


觉得本文有帮助?欢迎点赞并分享给更多的人。

阅读更多更新文章,请关注微信公众号【面向对象思考】

发布了408 篇原创文章 · 获赞 653 · 访问量 29万+

猜你喜欢

转载自blog.csdn.net/craftsman1970/article/details/104432300
今日推荐