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
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.
Seems way more complicated than necessary. Why not just:
But in general, one should try not to carry bad Java habits over into C++.