C++ C++;:另一个简单的范围保护

C++ C++;:另一个简单的范围保护,c++,exception-safety,scopeguard,C++,Exception Safety,Scopeguard,让我们来问一下这个简单的范围保护: template <class T> struct finop_t { T& t; ~finop_t() { t(); } }; #define FINALLY__(l, cl) \ auto FIN ## l ## clo = cl; \ finop_t<decltype(FIN ## l ## clo)> FIN ## l ## fin { FIN ## l ## clo} #define F

让我们来问一下这个简单的范围保护:

template <class T>
struct finop_t {
    T& t;
    ~finop_t() { t(); }
};
#define FINALLY__(l, cl) \
    auto FIN ## l ## clo = cl; \
    finop_t<decltype(FIN ## l ## clo)> FIN ## l ## fin { FIN ## l ## clo}
#define FINALLY_(l, cl) FINALLY__(l, cl)
#define FINALLY(...) FINALLY_(__LINE__, ([=](){__VA_ARGS__}))

int main() {
    FINALLY( std::cout << "hello" << std::endl ; );
    std::cout << "one" << std::endl;
    FINALLY( std::cout << "world" << std::endl ; );
    std::cout << "second" << std::endl;
    return 0;
}
模板
结构finop\t{
T&T;
~finop_t(){t();}
};
#最终定义(l,cl)\
自动翅片##l##clo=cl\
finop#t FIN#l#FIN{FIN#l#clo}
#定义FINALLY(l,cl)FINALLY(l,cl)
#定义FINALLY(…)FINALLY_uuuu(uuu行,([=])({uuuu VA_uargs_uuu}))
int main(){

最后(std::cout是的,这是安全的。宏将lambda存储在局部变量中。局部变量的销毁顺序是固定的(与构造顺序相反)。因此,可以保证在相应的lambda(
FIN#l#clo
之前调用
~finop#t()
析构函数析构函数。

是的,它是安全的。宏将lambda存储在局部变量中。局部变量的销毁顺序是固定的(与构造顺序相反)。因此可以保证在相应lambda(
FIN#l#clo
之前调用
~FIN#l#clo)析构函数析构函数。

局部变量的销毁按其构造的相反顺序进行

这里有一种更有效的方法,它不需要引用,使用拷贝省略来构建lambda

注意,你可能想考虑[而不是],但这是由你来判断的。
#包括
模板
结构finop\t{
finop_t(t&&t):t(std::forward(t)){
T;
~finop_t(){t();}
};
模板
finop_t make_finop_t(F&F)
{
返回finop_t(std::forward(f));
}
#最终定义(l,cl)\
自动FIN##l##FIN=make#u finop_t(cl);
#定义FINALLY(l,cl)FINALLY(l,cl)
#定义FINALLY(…)FINALLY_uuuu(uuu行,([=])({uuuu VA_uargs_uuu}))
int main(){

最后(std::cout局部变量的破坏以其构造的相反顺序发生

这里有一种更有效的方法,它不需要引用,使用拷贝省略来构建lambda

注意,你可能想考虑[而不是],但这是由你来判断的。
#包括
模板
结构finop\t{
finop_t(t&&t):t(std::forward(t)){
T;
~finop_t(){t();}
};
模板
finop_t make_finop_t(F&F)
{
返回finop_t(std::forward(f));
}
#最终定义(l,cl)\
自动FIN##l##FIN=make#u finop_t(cl);
#定义FINALLY(l,cl)FINALLY(l,cl)
#定义FINALLY(…)FINALLY_uuuu(uuu行,([=])({uuuu VA_uargs_uuu}))
int main(){


最后(std::cout进行编译?您正在为可变的l值引用分配一个临时变量。它进行编译。首先,我使用闭包值初始化变量
FIN#l#clo
。然后将对
FIN##########clo
变量
FIN##l########FIN
的字段
t
指定一个引用。啊,我明白了。在这种情况下,为什么不直接存储对象并初始化它呢?复制省略将确保没有多余的副本,也不会通过引用进行间接操作。如果你告诉我会很高兴。我没有第二种更简单的方法来对抗模板参数推断。好吧,我已经制作了一个简单的版本,它依赖于复制省略。这个编译吗?你给一个可变的l值引用分配了一个临时值。它确实编译。首先,我用闭包值初始化变量
FIN#l###clo
。(也许,复制省略在这里有点帮助)。然后将对
FIN##########clo
变量
FIN##l########FIN
的字段
t
指定一个引用。啊,我明白了。在这种情况下,为什么不直接存储对象并初始化它呢?复制省略将确保没有多余的副本,也不会通过引用进行间接操作。如果你告诉我会很高兴。我没有第二种更简单的方法来对抗模板参数推断。好吧,我已经制作了一个简单的版本,它依赖于复制省略。这几乎和我的版本一样,但我认为在析构函数中依赖复制省略不是一件好事(但可能是这样)。哦,感谢您指向
[&]
!!!这真的很有意义。在析构函数期间没有复制省略。它发生在调用
make\u finop\u t()
期间,从
make\u finop\u t()返回时作为RVO(返回值优化)
-c++11一路为我们提供了完美的转发功能。>>在析构函数中没有复制省略。如果将
-fno elide构造函数
标志传递给编译器(如@dyp中所示),它将被复制。这与我的版本几乎相同,但我认为在析构函数中依赖复制省略不是一件好事(但可能是,它是)。噢,感谢您指向
[&]
!!!这真的很有意义。在析构函数期间没有复制省略。它发生在调用
make\u finop\u t()
期间,从
make\u finop\u t()返回时作为RVO(返回值优化)
-c++11一路为我们提供了完美的转发功能。>>在析构函数期间没有复制省略。如果
-fno elide构造函数
标志传递给编译器,则会复制它(如@dyp中所示)
#include <iostream>

template <class T>
struct finop_t {
    finop_t(T&& t) : t(std::forward<T>(t)) {}
    T t;
    ~finop_t() { t(); }
};

template<class F>
finop_t<F> make_finop_t(F&& f)
{
    return finop_t<F>(std::forward<F>(f));
}

#define FINALLY__(l, cl) \
auto FIN ## l ## fin = make_finop_t(cl);

#define FINALLY_(l, cl) FINALLY__(l, cl)
#define FINALLY(...) FINALLY_(__LINE__, ([=](){__VA_ARGS__}))

int main() {
    FINALLY( std::cout << "hello" << std::endl ; );
    std::cout << "one" << std::endl;
    FINALLY( std::cout << "world" << std::endl ; );
    std::cout << "second" << std::endl;
    return 0;
}