C++核心準(zhǔn)則C.42:如果構(gòu)造函數(shù)不能生成合法對(duì)象就拋出異常

C.42: If a constructor cannot construct a valid object, throw an exception
C.42:如果構(gòu)造函數(shù)不能生成合法對(duì)象就拋出異常
Reason(原因)
Leaving behind an invalid object is asking for trouble.
將無(wú)效對(duì)象留給后續(xù)處理就等于是自找麻煩。
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.
變量定義(例如在堆棧或者作為其他對(duì)象的成員)不存在用于返回錯(cuò)誤代碼的明確的函數(shù)調(diào)用。留給后續(xù)處理一個(gè)無(wú)效對(duì)象并且依靠用戶在使用之前總是通過(guò)一個(gè)is_valid()函數(shù)進(jìn)行檢查的做法是乏味的,易錯(cuò)和低效的。
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.
有些領(lǐng)域,例如硬實(shí)時(shí)系統(tǒng)(例如飛機(jī)控制),它們(如果沒(méi)有另外的工具支持)從時(shí)機(jī)的方面來(lái)講異常處理不是充分可預(yù)測(cè)的。這里必須采用is_valid()技術(shù)。在這樣的情況下,需要自始至終地檢查is_valid()并且立刻模仿RAII的行為。

1.RAII是Resource Acquisition Is Initialization(wiki上面翻譯成 “資源獲取就是初始化”)的簡(jiǎn)稱,是C++語(yǔ)言的一種管理資源、避免泄漏的慣用法。鏈接:https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rr-raii
2.硬實(shí)時(shí)系統(tǒng)無(wú)法終端程序執(zhí)行,因此無(wú)法拋出異常。

Alternative(其他選項(xiàng))
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.
如果想要使用前置條件初始化或者兩階段初始化,不要那么做。如果你真的必須那樣做,考慮工廠函數(shù)。

工廠函數(shù):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()函數(shù)而不是在構(gòu)造函數(shù)內(nèi)部進(jìn)行初始化處理是希望避免代碼重復(fù)。委托構(gòu)造函數(shù)和默認(rèn)成員初始化可以做地更好。另外一個(gè)原始是希望將對(duì)象的初始化延遲到它被使用之前;解決方法通常是等到變量可以被正確的初始化時(shí)在聲明它。

委托構(gòu)造函數(shù):https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rc-delegating

Enforcement(實(shí)施建議)
???
原文鏈接
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#c42-if-a-constructor-cannot-construct-a-valid-object-throw-an-exception
覺(jué)得本文有幫助?請(qǐng)分享給更多人。
關(guān)注【面向?qū)ο笏伎肌枯p松學(xué)習(xí)每一天!
面向?qū)ο箝_(kāi)發(fā),面向?qū)ο笏伎迹?/span>
