C++ 什么是C+中的标准延迟/终结器实现+;?

C++ 什么是C+中的标准延迟/终结器实现+;?,c++,boost,go,stl,raii,C++,Boost,Go,Stl,Raii,解释和说明了Golang风格的一般思想defer 我想知道,STL(C++11,C++14,…)或者Boost或者其他库是否包含这样一个类的实现?因此,我可以直接使用它,而不用在每个新项目中重新实现它。有一个 auto file=make_unique_resource(::fopen(filename.c_str(),"w"),&::fclose); 对于资源,它定义了一个通用的范围\u退出,它应该与延迟相同: // Always say goodbye before returni

解释和说明了Golang风格的一般思想
defer

我想知道,STL(C++11,C++14,…)或者Boost或者其他库是否包含这样一个类的实现?因此,我可以直接使用它,而不用在每个新项目中重新实现它。

有一个

auto file=make_unique_resource(::fopen(filename.c_str(),"w"),&::fclose);
对于资源,它定义了一个通用的
范围\u退出
,它应该与
延迟
相同:

// Always say goodbye before returning,
auto goodbye = make_scope_exit([&out]() ->void
{
out << "Goodbye world..." << std::endl;
});
//总是在回来之前说再见,
自动再见=使范围退出([&out]()->无效
{

在新标准出台之前,我使用简单的RAII类:

struct ScopeGuard {
    typedef std::function< void() > func_type;
    explicit ScopeGuard(func_type _func) : func(_func), isReleased(false) {}
    ~ScopeGuard() {
        if( !isReleased && func ) try {
            func();
        }catch(...) {};
    }
    void Forget() { isReleased=true; }

    //noncopyable
    ScopeGuard(const ScopeGuard&) = delete;
    ScopeGuard& operator=(const ScopeGuard&) = delete;

private:
    func_type func;
    bool isReleased;
};

此外,您还可以使用Boost.ScopeExit和类似的实现。

这是我的解决方案,与您在swift中遇到的类型类似,但我不处理任何异常(如果需要,可以很容易地添加,只需使用类似于PSIAlt解决方案的try/catch块):

类延迟{
使用F=std::函数;
std::向量函数;
无效添加(F){
功能推回(f);
}
公众:
延迟(F){add(F);}
延迟(){}
延迟(const Defer&)=删除;
延迟&运算符=(常量延迟&)=删除;
void运算符()(F){add(F);}
~Defer(){
对于(;!funcs.empty();){
funcs.back();
funcs.pop_back();
}
}
};
由于使用了vector,它可能看起来很笨重,但它保留了swift的defer行为,其中函数以相反的顺序调用:

Defer defer([]{std::cout << "fourth" << std::endl;});
std::cout << "first" << std::endl;
auto s = "third";
defer([&s]{std::cout << s << std::endl;});
std::cout << "second" << std::endl;
Defer-Defer([]{std::cout这样使用:

int main()   {
    int  age = 20;
    DEFER { std::cout << "age = " << age << std::endl; };
    DEFER { std::cout << "I'll be first\n"; };
}
#include "auto.h"

int main(int argc, char **argv)
{
    Auto(std::cout << "Goodbye world" << std::endl);  // defer a single statement...
    int x[4], *p = x;
    Auto(
        if (p != x) {  // ...or a whole block's worth of control flow
            delete p;
        }
    );
    if (argc > 4) { p = new int[argc]; }
}
#pragma once

template <class Lambda> class AtScopeExit {
  Lambda& m_lambda;
public:
  AtScopeExit(Lambda& action) : m_lambda(action) {}
  ~AtScopeExit() { m_lambda(); }
};

#define Auto_INTERNAL2(lname, aname, ...) \
    auto lname = [&]() { __VA_ARGS__; }; \
    AtScopeExit<decltype(lname)> aname(lname);

#define Auto_TOKENPASTE(x, y) Auto_ ## x ## y

#define Auto_INTERNAL1(ctr, ...) \
    Auto_INTERNAL2(Auto_TOKENPASTE(func_, ctr), \
                   Auto_TOKENPASTE(instance_, ctr), __VA_ARGS__)

#define Auto(...) Auto_INTERNAL1(__COUNTER__, __VA_ARGS__)
#include <iostream>
#include "defer.hpp"

using namespace std;

int main() {
    defer []{cout << "defered" << endl;};
}
intmain(){
年龄=20岁;

延迟{std::cout我在CppCon 2014()上提出了一个只使用标题的Go风格的延迟实现;我称之为
Auto
。就可教性、效率和绝对的傻瓜性而言,这仍然是最好的选择。在使用中,它看起来如下:

int main()   {
    int  age = 20;
    DEFER { std::cout << "age = " << age << std::endl; };
    DEFER { std::cout << "I'll be first\n"; };
}
#include "auto.h"

int main(int argc, char **argv)
{
    Auto(std::cout << "Goodbye world" << std::endl);  // defer a single statement...
    int x[4], *p = x;
    Auto(
        if (p != x) {  // ...or a whole block's worth of control flow
            delete p;
        }
    );
    if (argc > 4) { p = new int[argc]; }
}
#pragma once

template <class Lambda> class AtScopeExit {
  Lambda& m_lambda;
public:
  AtScopeExit(Lambda& action) : m_lambda(action) {}
  ~AtScopeExit() { m_lambda(); }
};

#define Auto_INTERNAL2(lname, aname, ...) \
    auto lname = [&]() { __VA_ARGS__; }; \
    AtScopeExit<decltype(lname)> aname(lname);

#define Auto_TOKENPASTE(x, y) Auto_ ## x ## y

#define Auto_INTERNAL1(ctr, ...) \
    Auto_INTERNAL2(Auto_TOKENPASTE(func_, ctr), \
                   Auto_TOKENPASTE(instance_, ctr), __VA_ARGS__)

#define Auto(...) Auto_INTERNAL1(__COUNTER__, __VA_ARGS__)
#include <iostream>
#include "defer.hpp"

using namespace std;

int main() {
    defer []{cout << "defered" << endl;};
}
#包括“auto.h”
int main(int argc,字符**argv)
{

Auto(std::cout这个实现与其他一些答案不同,是零开销的,而且语法更好,更易于使用。它还具有零依赖性,减少了编译时间

您可以将此代码段粘贴到代码库中的任何位置,它将正常工作

#ifndef defer
struct defer_dummy {};
template <class F> struct deferrer { F f; ~deferrer() { f(); } };
template <class F> deferrer<F> operator*(defer_dummy, F f) { return {f}; }
#define DEFER_(LINE) zz_defer##LINE
#define DEFER(LINE) DEFER_(LINE)
#define defer auto DEFER(__LINE__) = defer_dummy{} *[&]()
#endif // defer

注意:本地延迟器对象以
zz\uz
开始,而不是
\uz
因此它不会扰乱调试器中的本地窗口,而且还因为用户标识符在技术上不应该以下划线开始。

这是我的延迟实现,但没有异常保证,我仍然认为它不是很好的实现

这样使用:

int main()   {
    int  age = 20;
    DEFER { std::cout << "age = " << age << std::endl; };
    DEFER { std::cout << "I'll be first\n"; };
}
#include "auto.h"

int main(int argc, char **argv)
{
    Auto(std::cout << "Goodbye world" << std::endl);  // defer a single statement...
    int x[4], *p = x;
    Auto(
        if (p != x) {  // ...or a whole block's worth of control flow
            delete p;
        }
    );
    if (argc > 4) { p = new int[argc]; }
}
#pragma once

template <class Lambda> class AtScopeExit {
  Lambda& m_lambda;
public:
  AtScopeExit(Lambda& action) : m_lambda(action) {}
  ~AtScopeExit() { m_lambda(); }
};

#define Auto_INTERNAL2(lname, aname, ...) \
    auto lname = [&]() { __VA_ARGS__; }; \
    AtScopeExit<decltype(lname)> aname(lname);

#define Auto_TOKENPASTE(x, y) Auto_ ## x ## y

#define Auto_INTERNAL1(ctr, ...) \
    Auto_INTERNAL2(Auto_TOKENPASTE(func_, ctr), \
                   Auto_TOKENPASTE(instance_, ctr), __VA_ARGS__)

#define Auto(...) Auto_INTERNAL1(__COUNTER__, __VA_ARGS__)
#include <iostream>
#include "defer.hpp"

using namespace std;

int main() {
    defer []{cout << "defered" << endl;};
}
#包括
#包括“defer.hpp”
使用名称空间std;
int main(){
defer[]{cout提供了defer实现(,)。用法如下:

void myfunc(){
延迟([])(){
printf(“离开…\n”);
});
...
}
延迟
本身实现为:

//defer(f)模仿golang的'defer f()'。
//注:和Go相反,f在当前作用域的末尾被调用,而不是函数。
#定义延迟(f)golang::_deferred _deferred uuu(uuu计数器uuu)(f)
#定义延迟(计数器)\u延迟2(计数器)
#定义_defer_2(计数器)_defer_##计数器
结构延迟{
类型定义函数F;
F;
_延期(F):F(F){}
~_deferred(){f();}
私人:
_延迟(const _deferred&)//不复制
_延迟(_deferred&&);//不要移动
};

STL没有。但这两个链接都提供了小样本(几行)使用C++11代码来实现您所寻求的行为,因此您可能会花费更多的时间来尝试找到一个提供该功能的库,而不是使用自己的库。当然还有
unique\u ptr
,它已经完成了90%的相同功能;此外还有一些功能提升。您能告诉我,我太懒了,无法真正写出答案:)我也想使用unique_ptr,但是它会有一个伪指针,我想用NULL来填充。但是如果我这样做了,它会调用deleter吗?@Jens:坏消息;@nicolas是的,我想我不是唯一一个对下一个标准有点失望的人。没有概念,没有模块,但至少有一堆库exte扩展。我想知道是否最好将库拆分为自己的标准。语言发展缓慢,但库的发展应该快于三年周期。@AdrianRatnapala当内部指针为
nullptr
时,删除程序将不会被调用。对不起,在本例中ScopeGuard不应该绑定到任何变量吗?可悲的是,在这里使用
std::function
会杀死你的codegen;你真的不想这么做。请参阅从10m58s开始。可悲的是,在这里使用
std::function
会杀死你的codegen;你真的不想这么做。请参阅从10m58s开始。模板化它有什么好处(F类)?它始终是
函数
。延迟块不接受任何参数,但通过引用捕获整个范围。具有捕获的lambda不能隐式转换为,例如,
void(*)()
,因为捕获需要存储。使用
std::function
是可行的,但由于捕获列表很大,可能会导致堆分配风险。通过将捕获保留在堆栈上,这个答案可以让编译器内联整个块,从而产生零开销延迟。在godbolt上进行了测试,你是对的。我认为没有任何东西会进入堆否则,使用STD::函数在使用零开销的情况下留下大量的样板。我仍然有点惊讶C++有两个不同的lambda结构,STD::函数和一个未指定类型的本地的魔法。如果它们是相同的,那就好了。不是C++有两个lambda构造,而是lambda不可能都有相同的类型,所以委员会标准库设计的一个非常低效的类型擦除结构来概括函数对象。