C++ 自动终结或对象销毁
C++ automatic finalization or objects destruction
在这个例子中我遇到了复制代码的问题:
void BadExample1() {
if (!Initialize1())
return;
if (!Initialize2()) {
Finalize1();
return;
}
if (!Initialize3()) {
Finalize1();
Finalize2();
return;
}
if (!Initialize4()) {
Finalize1();
Finalize2();
Finalize3();
return;
}
// some code..
Finalize1();
Finalize2();
Finalize3();
Finalize4();
}
Bnd 这是一个错误的代码结构。如果我有很多构造,代码的宽度会太大,这也很糟糕:
void BadExample2() {
if (Initialize1()) {
if (Initialize2()) {
if (Initialize3()) {
if (Initialize4()) {
if (Initialize5()) {
// some code..
Finalize5();
}
Finalize4();
}
Finalize3();
}
Finalize2();
}
Finalize1();
}
}
如何保存好的代码结构,解决代码抄袭问题?
Finalize1/2/3 是一个 API 函数而不是我的程序 类。
也许一些STL容器可以解决它?
也许是这样的?
void GoodExample() {
if (!Initialize1())
return;
RaiiWrapper<void(*)()> raii_wrapper1([]() {
Finalize1();
});
if (!Initialize2()) {
//Finalize1();
return;
}
RaiiWrapper<void(*)()> raii_wrapper2([]() {
Finalize2();
});
if (!Initialize3()) {
//Finalize1();
//Finalize2();
return;
}
RaiiWrapper<void(*)()> raii_wrapper3([]() {
Finalize3();
});
if (!Initialize4()) {
//Finalize1();
//Finalize2();
//Finalize3();
return;
}
RaiiWrapper<void(*)()> raii_wrapper4([]() {
Finalize4();
});
// some code..
//Finalize1();
//Finalize2();
//Finalize3();
//Finalize4();
}
每当您从 API 获得宝贵的资源时,您需要使用适当的析构函数将其包装为一个对象。所以,如果 Initialize1
初始化 something1
那么 something1
实际上应该是一个知道如何初始化和如何完成自身的对象 Something1
。此外,初始化失败应该抛出异常(fstream
没有这样做,因为 fstream
比这个概念更早)。
class Something1 {
public: Something1 () { if (!Initialize1()) throw resource_failed ("1"); }
~Something1 () { Finalize1(); }
}
为什么不用实物?
struct SetupPart1 {
SetupPart1 () { if (!Initialize1() throw std::runtime_error("Part1"); }
~SetupPart1 () { Finalize1(); }
};
第 2、3、4 部分依此类推。
现在您的示例如下所示:
void GoodExample() {
try {
SetupPart1 p1;
SetupPart2 p2;
SetupPart3 p3;
SetupPart4 p4;
// some code ...
}
catch { const std::runtime_error &ex ) {
std::cerr << "GoodExample Failed: " << ex.what << std::end;
}
}
您可以简化 Marshall 的建议并使用 not-yet-standardized std::make_unique_resource()
(此功能与 scope_guard
密切相关,Andrei Alexandrescu 几年前建议的一个装置也在该提案中).这为您提供了一个具有两个功能的对象 - 一个在变量范围的开始处到 运行,另一个在其结尾处到 运行(即分别在构造和销毁时)。
然后,不用定义四个单独的 classes,您只需编写:
void GoodExample() {
auto r1 = std::make_unique_resource(Initialize1, Finalize1);
auto r2 = std::make_unique_resource(Initialize2, Finalize2);
auto r3 = std::make_unique_resource(Initialize3, Finalize3);
auto r4 = std::make_unique_resource(Initialize4, Finalize4);
// some code
}
提案有实现代码;并且 - 它一点也不复杂。所以你可以只复制实现并创建你自己的 not_std::make_unique_resource()
函数和相关的模板化 class(es).
在这个例子中我遇到了复制代码的问题:
void BadExample1() {
if (!Initialize1())
return;
if (!Initialize2()) {
Finalize1();
return;
}
if (!Initialize3()) {
Finalize1();
Finalize2();
return;
}
if (!Initialize4()) {
Finalize1();
Finalize2();
Finalize3();
return;
}
// some code..
Finalize1();
Finalize2();
Finalize3();
Finalize4();
}
Bnd 这是一个错误的代码结构。如果我有很多构造,代码的宽度会太大,这也很糟糕:
void BadExample2() {
if (Initialize1()) {
if (Initialize2()) {
if (Initialize3()) {
if (Initialize4()) {
if (Initialize5()) {
// some code..
Finalize5();
}
Finalize4();
}
Finalize3();
}
Finalize2();
}
Finalize1();
}
}
如何保存好的代码结构,解决代码抄袭问题? Finalize1/2/3 是一个 API 函数而不是我的程序 类。 也许一些STL容器可以解决它? 也许是这样的?
void GoodExample() {
if (!Initialize1())
return;
RaiiWrapper<void(*)()> raii_wrapper1([]() {
Finalize1();
});
if (!Initialize2()) {
//Finalize1();
return;
}
RaiiWrapper<void(*)()> raii_wrapper2([]() {
Finalize2();
});
if (!Initialize3()) {
//Finalize1();
//Finalize2();
return;
}
RaiiWrapper<void(*)()> raii_wrapper3([]() {
Finalize3();
});
if (!Initialize4()) {
//Finalize1();
//Finalize2();
//Finalize3();
return;
}
RaiiWrapper<void(*)()> raii_wrapper4([]() {
Finalize4();
});
// some code..
//Finalize1();
//Finalize2();
//Finalize3();
//Finalize4();
}
每当您从 API 获得宝贵的资源时,您需要使用适当的析构函数将其包装为一个对象。所以,如果 Initialize1
初始化 something1
那么 something1
实际上应该是一个知道如何初始化和如何完成自身的对象 Something1
。此外,初始化失败应该抛出异常(fstream
没有这样做,因为 fstream
比这个概念更早)。
class Something1 {
public: Something1 () { if (!Initialize1()) throw resource_failed ("1"); }
~Something1 () { Finalize1(); }
}
为什么不用实物?
struct SetupPart1 {
SetupPart1 () { if (!Initialize1() throw std::runtime_error("Part1"); }
~SetupPart1 () { Finalize1(); }
};
第 2、3、4 部分依此类推。 现在您的示例如下所示:
void GoodExample() {
try {
SetupPart1 p1;
SetupPart2 p2;
SetupPart3 p3;
SetupPart4 p4;
// some code ...
}
catch { const std::runtime_error &ex ) {
std::cerr << "GoodExample Failed: " << ex.what << std::end;
}
}
您可以简化 Marshall 的建议并使用 not-yet-standardized std::make_unique_resource()
(此功能与 scope_guard
密切相关,Andrei Alexandrescu 几年前建议的一个装置也在该提案中).这为您提供了一个具有两个功能的对象 - 一个在变量范围的开始处到 运行,另一个在其结尾处到 运行(即分别在构造和销毁时)。
然后,不用定义四个单独的 classes,您只需编写:
void GoodExample() {
auto r1 = std::make_unique_resource(Initialize1, Finalize1);
auto r2 = std::make_unique_resource(Initialize2, Finalize2);
auto r3 = std::make_unique_resource(Initialize3, Finalize3);
auto r4 = std::make_unique_resource(Initialize4, Finalize4);
// some code
}
提案有实现代码;并且 - 它一点也不复杂。所以你可以只复制实现并创建你自己的 not_std::make_unique_resource()
函数和相关的模板化 class(es).