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

面向对象思考

共 3391字,需浏览 7分钟

 ·

2019-12-28 23:26

e7577fa926b91c23fa11b41dedd66376.webp

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

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


955ffece76384c81065f880a24e90fc3.webpReason(原因)9ca2ca5475bde2f4385727b698be9f79.webp

Leaving behind an invalid object is asking for trouble.

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

955ffece76384c81065f880a24e90fc3.webpExample(示例)9ca2ca5475bde2f4385727b698be9f79.webp


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
   // ...
}

955ffece76384c81065f880a24e90fc3.webpExample, bad(反面示例)9ca2ca5475bde2f4385727b698be9f79.webp


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 ...
   }
   // ...
}

955ffece76384c81065f880a24e90fc3.webpNote(注意)9ca2ca5475bde2f4385727b698be9f79.webp

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()函数进行检查的做法是乏味的,易错和低效的。

955ffece76384c81065f880a24e90fc3.webpException(例外)9ca2ca5475bde2f4385727b698be9f79.webp

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的行为。

013d1e6e00e8461582b30a68d8cc2d0a.webp

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

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

ad627c286f0f9a2e06bf76f1686dd134.webp955ffece76384c81065f880a24e90fc3.webpAlternative(其他选项)9ca2ca5475bde2f4385727b698be9f79.webp

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.

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

013d1e6e00e8461582b30a68d8cc2d0a.webp

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

ad627c286f0f9a2e06bf76f1686dd134.webp955ffece76384c81065f880a24e90fc3.webpNote(注意)9ca2ca5475bde2f4385727b698be9f79.webp

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

013d1e6e00e8461582b30a68d8cc2d0a.webp

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

ad627c286f0f9a2e06bf76f1686dd134.webp955ffece76384c81065f880a24e90fc3.webpEnforcement(实施建议)9ca2ca5475bde2f4385727b698be9f79.webp

???

955ffece76384c81065f880a24e90fc3.webp原文链接9ca2ca5475bde2f4385727b698be9f79.webp

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




觉得本文有帮助?请分享给更多人。

关注【面向对象思考】轻松学习每一天!

面向对象开发,面向对象思考!


浏览 19
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报