容器如何处理 lambda 表达式的参数
How container handles the arguments of a lambda expression
继几个月前我之前的问题之后,我想问一个容器如何在内部处理lampda表达式。
假设以下代码段:
#include <iostream>
#include <type_traits>
#include <queue>
#include <functional>
std::queue<std::function<void()>> funcs;
class A
{
public:
A()
{
std::cout << "A constructor" << std::endl;
}
void foo(int a)
{
}
};
class ThePool
{
public:
template <typename _Callable, typename Object, typename... _Args>
void QueueFunction(_Callable __f, Object& obj, _Args... __args)
{
funcs.push([__f, &obj, &__args...]() mutable
{
(obj.*__f)(__args...);
});
}
};
int main(int argc, char** argv)
{
ThePool t;
A a;
int x = 5;
t.QueueFunction(&A::foo, a, x);
std::function<void()> func = funcs.back();
func();
return 0;
}
如果将类 A 和 args 的实例作为值传递,则很明显这些值被复制。我混淆了如果我将类 A 的实例作为引用和 args 作为引用传递会发生什么。我知道在容器内部复制发生。从我的角度来看,函数指针的地址将被复制。是否也要复制 obj 和参数的实例?
举个例子,我注意到当我传递 A 实例作为引用并最终提取队列的函数 f 并将其称为 A 实例时,这是不一样的。
容器确实可以自由复制其元素。此外,std::function
要求存储的函子是CopyConstructible
的,它肯定会使用它。因此,您必须选择:
-
如果按值传递对象,则实际上不必担心对象生存期。但是,在对象的副本(或使用复制的参数(上调用成员函数可能不是您想要的。
-
如果通过(某种形式的(引用传递对象(例如,将它们包装在
std::ref
中(,您将永远不会创建对象和参数的副本,但在调用排队成员函数之前,它们可能会超出范围。
目前,在您的原始代码中,您正在 lambda 中创建obj
的副本(obj
是一个Obj&
但这对 lambda 捕获无关紧要 - 如果没有通过引用显式捕获,它会复制(。要在 lambda 中保留引用,请按引用 ([&obj]
捕获obj
,而不是按值捕获。或者,传递包裹在std::ref
中的对象。
至于参数,它们目前都是复制的(无论是在QueueFunction
还是在 lambda 捕获中(。如果这不是您的意图,请参阅上文。
如果存储引用,则开头提到的所有复制操作将只复制引用(而不是对象(。
相关文章:
- 这 4 个 lambda 表达式之间有什么区别?
- 使用成员在类中创建 lambda 表达式
- 将 lambda 表达式传递给 std::function in C++
- 在 lambda 表达式中使用 std::atomic
- &&对lambda表达式有什么好处?
- Tbb 库:错误:编写自定义类函数而不是 lambda 表达式时,对函数的调用不匹配
- 列表.erase 中的 lambda 表达式
- 使用 lambda 表达式的 Raspbian G++ 8.3.0 导致 ']' 之前的预期主表达式 - 即使标准设置为 c++14
- 仅通过引用捕获的 lambda 表达式是否保证不会抛出?
- C++: priority_queue:模板参数中的 lambda 表达式
- 容器如何处理 lambda 表达式的参数
- 在C++ Lambda 表达式中,为什么人们更喜欢按值捕获而不是作为参数传递?
- 如何在 lambda 表达式中传递变量?
- 针对 std::function 的 lambda 表达式和模板推导:为什么会这样?
- 如何修改Lambda表达式以将输出放入文本文件
- C++如何使用lambda表达式来捕获上一次迭代的值
- 为什么Qt在信号和插槽中为lambda表达式抛出错误?
- C++:从捕获函数参数的函数返回 lambda 表达式
- C++ Lambda 表达式:通过 ref 开销捕获
- Qt 连接无法识别 lambda 表达式