我在C ++ 11中使用lambda创建了 finally 模拟器,如下所示:
#include <cstdio>
template<typename Functor>
struct Finalizer
{
Finalizer(Functor& func) : func_(func) {} // (1)
~Finalizer() { func_(); }
private:
Functor func_; // (2)
};
template<typename functor>
Finalizer<functor> finally(functor& func)
{
return Finalizer<functor>(func); (3)
}
int main()
{
int a = 20;
// print the value of a at the escape of the scope
auto finalizer = finally([&]{ printf("%d\n", a); }); // (4)
}
代码按预期工作,但在 Finalizer struct(1)的ctor处有不受欢迎的复制ctor调用(lambda functor)。 (值得庆幸的是,RVO避免在最终函数(3 - &gt; 4)的return语句中进行复制构造。)
编译器不会消除copy ctor调用(至少在vc10中 - gcc可能会优化它),如果 Finalizer struct(2)中的functor类型被更改为引用它崩溃,因为最后调用(4)的lambda参数是r值。
当然,代码可以“优化”,如下所示
template<typename Functor>
struct Finalizer
{
Finalizer(Functor& func) : func_(func) {}
~Finalizer() { func_(); }
private:
Functor& func_;
};
int main()
{
int a = 20;
auto finalizer = [&]{ printf("%d\n", a); };
Finalizer<decltype(finalizer)> fin(finalizer);
}
没有开销,只有 printf 调用放在范围的末尾。但是......我不喜欢它。 :(我试图用宏包装它,但它需要声明两个“名称” - 一个用于lambda对象,另一个用于终结器对象。
我的目标很简单 -
在这种情况下有没有解决方法可以避免它?
答案 0 :(得分:4)
我认为lambdas有移动构造函数?如果是这样,和,如果您只在finally
内使用rvalues,那么&&
和forward
将移动而不是复制。
#include <cstdio>
template<typename Functor>
struct Finalizer
{
Finalizer(Functor&& func) : func_(std::forward(func)) {} // (1)
~Finalizer() { func_(); }
private:
Functor func_; // (2)
};
template<typename functor>
Finalizer<std::remove_reference<functor>::type> finally(functor&& func)
{
return Finalizer<std::remove_reference<functor>::type>(std::forward(func)); // (3)
}
int main()
{
int a = 20;
// print the value of a at the escape of the scope
auto finalizer = finally([&]{ printf("%d\n", a); }); // (4)
}
应该有可能找到一些更智能的东西,它也可以正确地与左值一起使用,这样你''优化'版本将编译并在它无法移动时复制。在这种情况下,我建议您使用类似Functor<std::remove_reference<functor>::type>
的内容来确保Functor的类型正确,无论参数是由&
还是&&
传递还是其他任何内容。
答案 1 :(得分:0)
也许接受构造函数的functor参数作为右值引用?
答案 2 :(得分:0)
我只是允许functions
通过值传递。
这是通过STL算法完成的。
然后,两种调用方式都可以:
auto finalizer = finally([&]{ printf("%d\n", a); }); // this can be dangerous, if passed by reference to finally.
auto finalizer = [&]{ printf("%d\n", a); };
Finalizer<decltype(finalizer)> fin(finalizer);
之所以这样做,是因为functions
不能太大。
我认为STL算法在传递functions
时遵循相同的推理。
这是完整的代码
#include <cstdio>
template<typename Functor>
struct Finalizer
{
Finalizer(Functor func) : func_(func) {} /// pass by value
~Finalizer() { func_(); }
private:
Functor func_; //
};
template<typename functor>
Finalizer<functor> finally(functor func) /// pass by value
{
return Finalizer<functor>(func);
}
int main()
{
int a = 20;
// print the value of a at the escape of the scope
auto finalizer = finally([&]{ printf("%d\n", a); });
}