Simuler enfin bloquer en C ++ 0x

Inspiré de l’autre sujet , j’ai écrit ce code qui simule un bloc finally :

 #include  #include  struct base { virtual ~base(){} }; template struct exec : base { TLambda lambda; exec(TLambda l) : lambda(l){} ~exec() { lambda(); } }; class lambda{ base *pbase; public: template lambda(TLambda l): pbase(new exec(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(); } 

Sortie ( ideone ):

 finally executed 

@Johannes semble penser que ce n’est pas tout à fait correct, et a commenté ceci :

Il peut se bloquer si le compilateur n’élimine pas le temporaire dans l’initialisation de la copie, car il supprime ensuite deux fois avec la même valeur de pointeur

J’aimerais savoir comment exactement. Aidez-moi à comprendre le problème 🙂


MODIFIER:

Problème résolu comme:

 class lambda{ base *pbase; public: template lambda(TLambda l): pbase(new exec(l)){} ~lambda() { delete pbase; } lambda(const lambda&)= delete; //disable copy ctor lambda& operator=(const lambda&)= delete; //disable copy assignment }; 

Et puis utilisez-le comme:

 //direct initialization, no copy-initialization lambda finally([&]{a=2; std::cout << "finally executed" << std::endl; }); 

Code complet: http://www.ideone.com/hsX0X

Dans cette initialisation:

 lambda finally = [&]{a=2; std::cout<<"finally executed";}; 

Le constructeur de copie implicitement défini pour lambda peut être utilisé. Cela ne fera que copier le pointeur brut pbase qui sera ensuite supprimé plusieurs fois.

Par exemple

 $ g++ -std=c++0x -Wall -Wextra -pedantic -fno-elide-constructors lambdafun.cc $ ./a.out a.out: lambdafun.cc:29: void A::start(): Assertion `a==1' failed. finally executedAborted (core dumped) 

En fait, votre assertion de tir masque le problème de la suppression double, mais cela montre le crash que je soulignais.

 $ g++ -std=c++0x -Wall -Wextra -pedantic -fno-elide-constructors -DNDEBUG lambdafun.cc $ ./a.out Segmentation fault (core dumped) 

Cela semble beaucoup plus compliqué que nécessaire. Pourquoi pas simplement:

 class finally { std::function const action; finally(const finally&) = delete; public: finally(std::function a) : action(a) {} ~finally() { action(); } }; 

Mais en général, il faut essayer de ne pas transférer les mauvaises habitudes Java en C ++.