为什么要调用dtor(使用annoymous/lambda func)

5 c++ lambda templates destructor c++11

我试图模仿最终的效果.所以我认为我应该进行快速的脏测试.

我们的想法是使用Most Important const来停止销毁并将finally块放在lambda中.然而,显然我做错了什么,并在MyFinally()结束时调用它.我该如何解决这个问题?

#include <cassert>
template<typename T>
class D{
    T fn;
public:
    D(T v):fn(v){}
    ~D(){fn();}
};

template<typename T>
const D<T>& MyFinally(T t) { return D<T>(t); }

int d;
class A{
    int a;
public:
    void start(){
        int a=1;
        auto v = MyFinally([&]{a=2;});
        try{
            assert(a==1);
            //do stuff
        }
        catch(int){
            //do stuff
        }
    }
};
int main() {
    A a;
    a.start();
}
Run Code Online (Sandbox Code Playgroud)

我的解决方案代码(注意:你最终不能在同一个块中有两个.正如期望的那样.但仍然有点脏)

#include <cassert>
template<typename T>
class D{
    T fn; bool exec;
public:
    D(T v):fn(v),exec(true){}
    //D(D const&)=delete //VS doesnt support this yet and i didnt feel like writing virtual=0
    D(D &&d):fn(move(d.fn)), exec(d.exec) {
      d.exec = false;
    }

    ~D(){if(exec) fn();}
};
template<typename T>
D<T> MyFinally(T t) { return D<T>(t); }


#define FINALLY(v) auto OnlyOneFinallyPlz = MyFinally(v)

int d;
class A{
public:
    int a;
    void start(){
        a=1;
        //auto v = MyFinally([&]{a=2;});
        FINALLY([&]{a=2;});
        try{
            assert(a==1);
            //do stuff
        }
        catch(int){
            FINALLY([&]{a=3;}); //ok, inside another scope
            try{
                assert(a==1);
                //do other stuff
            }
            catch(int){
                //do other stuff
            }
        }
    }
};
void main() {
    A a;
    a.start();
    assert(a.a==2);
}
Run Code Online (Sandbox Code Playgroud)

有趣的是,如果您在原始代码中删除了MyFinally中的&它可以正常工作-_-.

Joh*_*itb 5

// WRONG! returning a reference to a temporary that will be
// destroyed at the end of the function!
template<typename T>
const D<T>& MyFinally(T t) { return D<T>(t); }
Run Code Online (Sandbox Code Playgroud)

您可以通过引入移动构造函数来修复它

template<typename T>
class D{
    T fn;
    bool exec;

public:
    D(T v):fn(move(v)),exec(true){}

    D(D &&d):fn(move(d.fn)), exec(d.exec) {
      d.exec = false;
    }

    ~D(){if(exec) fn();}
};
Run Code Online (Sandbox Code Playgroud)

然后你可以重写你的玩具

template<typename T>
D<T> MyFinally(T t) { return D<T>(move(t)); }
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你.使用时不需要"const reference"技巧auto.请参阅此处了解如何在带有const引用的C++ 03中执行此操作.