在这种情况下,是否可以避免复制lambda函子
Is it possible to avoid copying lambda functor in this situation?
我在C++11中使用lambda制作了一个最终模拟器,如下所示:
#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("%dn", a); }); // (4)
}
代码按预期工作,但在Finalizer结构(1)的ctor处存在不需要的复制ctor调用(lambda函子的)。(值得庆幸的是,RVO避免了finally函数(3->4)中return语句的复制构造。)
编译器不会消除复制构造函数调用(至少在vc10中是这样-gcc可以优化它),如果Finalizer结构(2)中的函子类型被更改为引用,它将崩溃,因为最终调用(4)处的lambda参数是r-value。
当然,代码可以像下面的一样"优化"
template<typename Functor>
struct Finalizer
{
Finalizer(Functor& func) : func_(func) {}
~Finalizer() { func_(); }
private:
Functor& func_;
};
int main()
{
int a = 20;
auto finalizer = [&]{ printf("%dn", a); };
Finalizer<decltype(finalizer)> fin(finalizer);
}
没有开销,只有printf调用被放置在作用域的末尾。但是我不喜欢它。:(我试图用宏包装它,但它需要声明两个"名称"——一个用于lambda对象,另一个用于finalizer对象。
我的目标很简单-
- 应该消除所有可以避免的不必要的性能开销。理想情况下,不应该有函数调用,每个过程都应该内联
- 保持简洁的表达作为其效用函数的目的。允许使用宏,但不鼓励使用
对于这种情况,有什么解决方案可以避免吗?
我认为lambdas有move构造函数?如果是这样,和如果只在finally
中使用右值,则&&
和forward
将移动而不是复制。
#include <cstdio>
template<typename Functor>
struct Finalizer
{
Finalizer(Functor&& func) : func_(std::move(func)) {}
Finalizer(Functor const& func) : func_(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<functor>(func)); // (3)
}
int main()
{
int a = 20;
// print the value of a at the escape of the scope
auto finalizer = finally([&]{ printf("%dn", a); }); // (4)
}
应该可以纠正一些更智能的东西,这些东西也可以正确地使用lvalues,这样你的"优化"版本将编译,并在它无法移动时进行复制。在这种情况下,我建议您使用类似Functor<std::remove_reference<functor>::type>
的东西来确保Functor的类型正确,无论参数是由&
还是&&
传递的。
也许接受构造函数的函子参数作为右值引用?
我只允许通过值传递functions
。这是通过STL算法完成的。
然后,两种呼叫方式都可以:
- 这个
auto finalizer = finally([&]{ printf("%dn", a); }); // this can be dangerous, if passed by reference to finally.
- 这个
auto finalizer = [&]{ printf("%dn", 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("%dn", a); });
}
- 使lambda不可复制/不可移动
- 在 lambda 中锁定 std::shared_ptr 的复制操作
- 将参数传递给泛型 lambda 时复制构造函数不正确
- 如何确定捕获不可复制参数的 lambda 的类型?
- 复制分配C++相同类型的 lambda
- 为什么在直接初始化和赋值中传递 lambda 而不是在复制初始化中传递 lambda 时会编译?
- lambda[=] 上的复制值被另一个封装的 lambda[&] 阻止
- 是否可以避免将参数复制到 lambda 函数?
- 我的lambda在复制构建期间没有正确转换捕获的"this"
- 复制 std::vector,但将 lambda 应用于每个元素
- 可以使用默认参数复制包含 lambda 的 std::函数吗?
- 为什么通过复制捕获 lambda 具有与外部变量相同的地址
- 是否可以传递具有捕获的不可复制(移动)值的 lambda
- 未定义 Lambda 复制分配运算符
- C++不可复制的 lambda 的行为是可复制的
- 为什么我无法更改 lambda 函数中复制捕获的变量的值?
- 是否可以使用 lambda 初始化变量(删除复制 ctor 时)
- C++:如何从 lambda 中"un-capture"不可复制的内容(例如 unique_ptr)?
- 不可变的 lambda 函数:复制捕获的变量是否允许是 const
- 在这种情况下,是否可以避免复制lambda函子