【发布时间】:2015-12-14 10:55:10
【问题描述】:
这是来自 Stroustrup 的“C++ 编程语言”的代码,它实现了 finally,我无法理解它在哪里调用了析构函数。
template<typename F> struct Final_action
{
Final_action(F f): clean{f} {}
~Final_action() { clean(); }
F clean;
}
template<class F>
Final_action<F> finally(F f)
{
return Final_action<F>(f);
}
void test(){
int* p=new int{7};
auto act1 = finally( [&]{delete p;cout<<"Goodbye,cruel world\n";} );
}
我有两个问题:
根据作者的说法,
delete p只被调用一次:当 act1 超出范围时。但据我了解:首先,act1将使用复制构造函数进行初始化,然后函数finally中的临时对象Final_action<F>(f)被破坏,第一次调用delete p,最后第二次调用当act1超出范围时,函数test的作用。我哪里弄错了?为什么需要
finally函数?我不能只定义Final_action act1([&]{delete p;cout<<"Goodbye,cruel world\n"})吗?是一样的吗?
另外,如果有人能想到更好的标题,请修改当前标题。
更新:经过进一步思考,我现在确信析构函数可能会被调用三次。另外一个是在调用函数void test() 中自动生成的临时对象,用作act1 的复制构造函数的参数。这可以通过 g++ 中的-fno-elide-constructors 选项进行验证。对于那些和我有同样问题的人,请参阅比尔林奇的回答中指出的 Copy elision 和 Return value optimization。
【问题讨论】:
-
每个问题一个问题,请。
-
re #2 我不明白为什么不这样做。我猜有人痴迷于
auto认为这更容易阅读。 -
@LightnessRacesinOrbit 模板参数推导。由于 lambda,您实际上无法编写
Final_action<???>的类型。 -
再次阅读本章。复制构造函数和
operator=都设置为删除以防止Final_action被复制。此外,您的示例代码在cout之后至少缺少一个分号 -
@btshengsheng 一个 lambda 表达式创建一个函数对象(函子),它的类型是由编译器生成的。程序员不知道该类型的名称,但除此之外它是一个带有
operator ()的常规类。