在 C++0x 中模拟 finally 块
受到另一个主题的启发,我写了此代码模拟 finally
块:
#include <cassert>
#include <iostream>
struct base { virtual ~base(){} };
template<typename TLambda>
struct exec : base
{
TLambda lambda;
exec(TLambda l) : lambda(l){}
~exec() { lambda(); }
};
class lambda{
base *pbase;
public:
template<typename TLambda>
lambda(TLambda l): pbase(new exec<TLambda>(l)){}
~lambda() { delete pbase; }
};
class A{
int a;
public:
void start(){
int a=1;
lambda finally = [&]{a=2; std::cout<<"finally executed";};
try{
assert(a==1);
//do stuff
}
catch(int){
//do stuff
}
}
};
int main() {
A a;
a.start();
}
输出 (ideone):
finally executed
@Johannes似乎认为它并不完全正确,并且 评论说:
如果编译器不这样做,它可能会崩溃 删除副本中的临时内容 初始化,因为然后它 使用同一指针删除两次 值
我想知道具体 是多少。帮助我理解问题:-)
编辑:
问题修复为:
class lambda{
base *pbase;
public:
template<typename TLambda>
lambda(TLambda l): pbase(new exec<TLambda>(l)){}
~lambda() { delete pbase; }
lambda(const lambda&)= delete; //disable copy ctor
lambda& operator=(const lambda&)= delete; //disable copy assignment
};
然后将其用作:
//direct initialization, no copy-initialization
lambda finally([&]{a=2; std::cout << "finally executed" << std::endl; });
Inspired from the other topic, I wrote this code which simulates a finally
block:
#include <cassert>
#include <iostream>
struct base { virtual ~base(){} };
template<typename TLambda>
struct exec : base
{
TLambda lambda;
exec(TLambda l) : lambda(l){}
~exec() { lambda(); }
};
class lambda{
base *pbase;
public:
template<typename TLambda>
lambda(TLambda l): pbase(new exec<TLambda>(l)){}
~lambda() { delete pbase; }
};
class A{
int a;
public:
void start(){
int a=1;
lambda finally = [&]{a=2; std::cout<<"finally executed";};
try{
assert(a==1);
//do stuff
}
catch(int){
//do stuff
}
}
};
int main() {
A a;
a.start();
}
Output (ideone):
finally executed
@Johannes seems to think that its not entirely correct, and commented that:
It can crash if the compiler doesn't
elide the temporary in the copy
initialization, because then it
deletes twice with the same pointer
value
I would like to know how exactly. Help me understanding the problem :-)
EDIT:
Problem fixed as:
class lambda{
base *pbase;
public:
template<typename TLambda>
lambda(TLambda l): pbase(new exec<TLambda>(l)){}
~lambda() { delete pbase; }
lambda(const lambda&)= delete; //disable copy ctor
lambda& operator=(const lambda&)= delete; //disable copy assignment
};
And then use it as:
//direct initialization, no copy-initialization
lambda finally([&]{a=2; std::cout << "finally executed" << std::endl; });
Complete code : http://www.ideone.com/hsX0X
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在此初始化中:
可以使用 lambda 隐式定义的复制构造函数。这只会复制原始指针
pbase
,然后该指针将被多次删除。例如
,实际上,您的断言触发掩盖了双重删除问题,但这证明了我强调的崩溃。
In this initialization:
The implicitly defined copy constructor for
lambda
may be used. This will just copy the raw pointerpbase
which will then be deleted more than once.E.g.
Actually, your assert firing masks the double delete problem, but this demonstrates the crash I was highlighting.
看起来比必要的要复杂得多。为什么不只是:
但总的来说,人们应该尽量不要将不良的 Java 习惯带入 C++ 中。
Seems way more complicated than necessary. Why not just:
But in general, one should try not to carry bad Java habits over into C++.