C++核心準(zhǔn)則?NR.5:不要使用兩階段初始化

NR.5: Don't use two-phase initialization
NR.5:不要使用兩階段初始化
Reason(原因)
Splitting initialization into two leads to weaker invariants, more complicated code (having to deal with semi-constructed objects), and errors (when we didn't deal correctly with semi-constructed objects consistently).
將初始化分為兩部分會(huì)導(dǎo)致不變性較弱,代碼更復(fù)雜(必須處理半結(jié)構(gòu)化對(duì)象)和錯(cuò)誤(當(dāng)我們不能始終如一地正確處理半結(jié)構(gòu)化對(duì)象時(shí))。
Example, bad(反面示例)
// Old conventional style: many problems
class Picture
{
int mx;
int my;
char * data;
public:
// main problem: constructor does not fully construct
Picture(int x, int y)
{
mx = x; // also bad: assignment in constructor body
// rather than in member initializer
my = y;
data = nullptr; // also bad: constant initialization in constructor
// rather than in member initializer
}
~Picture()
{
Cleanup();
}
// ...
// bad: two-phase initialization
bool Init()
{
// invariant checks
if (mx <= 0 || my <= 0) {
return false;
}
if (data) {
return false;
}
data = (char*) malloc(mx*my*sizeof(int)); // also bad: owning raw * and malloc
return data != nullptr;
}
// also bad: no reason to make cleanup a separate function
void Cleanup()
{
if (data) free(data);
data = nullptr;
}
};
Picture picture(100, 0); // not ready-to-use picture here
// this will fail..
if (!picture.Init()) {
puts("Error, invalid picture");
}
// now have a invalid picture object instance.Example, good(范例)
class Picture
{
int mx;
int my;
vector data;
static int check_size(int size)
{
// invariant check
Expects(size > 0);
return size;
}
public:
// even better would be a class for a 2D Size as one single parameter
Picture(int x, int y)
: mx(check_size(x))
, my(check_size(y))
// now we know x and y have a valid size
, data(mx * my * sizeof(int)) // will throw std::bad_alloc on error
{
// picture is ready-to-use
}
// compiler generated dtor does the job. (also see C.21)
// ...
};
Picture picture1(100, 100);
// picture is ready-to-use here...
// not a valid size for y,
// default contract violation behavior will call std::terminate then
Picture picture2(100, 0);
// not reach here... Alternative(代替選項(xiàng))
Always establish a class invariant in a constructor.
始終在構(gòu)造函數(shù)中建立類不變式。
Don't define an object before it is needed.
不要在需要之前定義對(duì)象。
原文鏈接
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#nr5-dont-use-two-phase-initialization
新書(shū)介紹
《實(shí)戰(zhàn)Python設(shè)計(jì)模式》是作者最近出版的新書(shū),拜托多多關(guān)注!

本書(shū)利用Python 的標(biāo)準(zhǔn)GUI 工具包tkinter,通過(guò)可執(zhí)行的示例對(duì)23 個(gè)設(shè)計(jì)模式逐個(gè)進(jìn)行說(shuō)明。這樣一方面可以使讀者了解真實(shí)的軟件開(kāi)發(fā)工作中每個(gè)設(shè)計(jì)模式的運(yùn)用場(chǎng)景和想要解決的問(wèn)題;另一方面通過(guò)對(duì)這些問(wèn)題的解決過(guò)程進(jìn)行說(shuō)明,讓讀者明白在編寫(xiě)代碼時(shí)如何判斷使用設(shè)計(jì)模式的利弊,并合理運(yùn)用設(shè)計(jì)模式。
對(duì)設(shè)計(jì)模式感興趣而且希望隨學(xué)隨用的讀者通過(guò)本書(shū)可以快速跨越從理解到運(yùn)用的門檻;希望學(xué)習(xí)Python GUI 編程的讀者可以將本書(shū)中的示例作為設(shè)計(jì)和開(kāi)發(fā)的參考;使用Python 語(yǔ)言進(jìn)行圖像分析、數(shù)據(jù)處理工作的讀者可以直接以本書(shū)中的示例為基礎(chǔ),迅速構(gòu)建自己的系統(tǒng)架構(gòu)。
覺(jué)得本文有幫助?請(qǐng)分享給更多人。
關(guān)注微信公眾號(hào)【面向?qū)ο笏伎肌枯p松學(xué)習(xí)每一天!
面向?qū)ο箝_(kāi)發(fā),面向?qū)ο笏伎迹?/span>
