当使用 std::move 和 lambda 时,何时会发生移动
When using std::move with a lambda when does the move happen
如果我在函数中创建 lambda 并使用 std::move 捕获一个变量到 lambda,什么时候会发生移动?是在创建 lambda 时还是在执行 lambda 时?
以以下代码为例...各种动作何时发生?如果在一个线程上调用 myFunction,而在另一个线程上执行 testLambda,线程是否安全?
class MyClass {
private:
// Only accessed on thread B
std::vector<int> myStuff;
// Called from thread A with new data
void myFunction(const std::vector<int>&& theirStuff) {
// Stored to be called on thread B
auto testLambda = [this, _theirStuff{ std::move(theirStuff) }]() {
myStuff = std::move(_theirStuff);
};
// ... store lambda
}
// Elsewhere on thread A
void someOtherFunction() {
std::vector<int> newStuff = { 1, 2, .... n };
gGlobalMyClass->myFunction(std::move(newStuff));
}
如果我在函数中创建一个 lambda 并使用 std::move 捕获一个变量到lambda,什么时候会发生移动?是在创建 lambda 时还是在执行 lambda 时?
如果你写了我相信你打算写的东西,那么答案将是:两者兼而有之。目前,答案是:两者都不是。您有一个 lambda 捕获_theirStuff { std::move(theirStuff) }
.这基本上声明了闭包类型的一个成员,该成员将在创建闭包对象时初始化,就好像它是
auto _theirStuff { std::move(theirStuff) };
你也有
myStuff = std::move(_theirStuff);
在 lambda 正文中。
但是,您的参数theirStuff
实际上是对const std::vector<int>
的右值引用。因此,_theirStuff { std::move(theirStuff) }
实际上不会执行移动,因为无法从const std::vector
移动。最有可能的是,你想写std::vector<int>&& theirStuff
。此外,正如@JVApen在下面的评论中指出的那样,您的 lambda 是不可变的。因此,_theirStuff
实际上也是常量,因此也无法移动。因此,尽管有所有std::move
,您上面的代码实际上每次都会复制向量。如果你写过
void myFunction(std::vector<int>&& theirStuff)
{
auto testLambda = [this, _theirStuff { std::move(theirStuff) }]() {
myStuff = std::move(_theirStuff);
};
}
创建闭包对象时,您将theirStuff
移动到_theirStuff
中。当调用 lambda 时,您将_theirStuff
复制到myStuff
中。如果你写过
void myFunction(std::vector<int>&& theirStuff)
{
auto testLambda = [this, _theirStuff { std::move(theirStuff) }]() mutable {
myStuff = std::move(_theirStuff);
};
}
然后,您将在创建闭包对象时将theirStuff
移动到_theirStuff
中。当调用 lambda 时,您将_theirStuff
移动到myStuff
中。请注意,因此,您的 lambda 实际上不能被调用两次。我的意思是,它可以,但它只会真正工作一次,因为_theirStuff
第一次调用 lambda 后将是空的......
另请注意,上述描述仅对示例中的特定类型组合有效。对于移动对象的实际含义,没有通用的定义。移动对象的含义完全取决于对象的特定类型。它甚至可能没有任何意义。std::move
本身并没有真正做任何事情。它所做的只是将给定的表达式强制转换为右值引用。如果随后从std::move
的结果初始化另一个对象,或将结果分配给对象,重载解析将选取移动构造函数或移动赋值运算符(如果存在),而不是普通的复制构造函数或复制赋值运算符。然后由相应类型的移动构造函数/移动赋值运算符的实现来实际执行移动,即,在初始化或从右值赋值的情况下,为特定类型执行任何应该做的事情。因此,在某种程度上,当您应用std::move
时,您要做的是将相应的对象宣传为"这可能会被移动"。它是否真的会被移出(如果是这样,这实际上意味着什么)取决于实现。在std::vector
的特殊情况下,根据定义,移动构造函数/移动赋值运算符不仅保证原始向量的内容将从原始对象接管,而且原始对象之后将为空。在许多其他情况下,对从中移动的对象执行任何操作都可能是未定义的行为(除了,也许,销毁它;该对象几乎可以被视为一种类型,至少不允许这样做几乎是无用的;通常,您至少能够为从中移动的对象分配一个新值, 但即使这样也不能保证)。您始终必须检查手头的特定类型,对象在从
- 在以唯一ptr为值的C++映射中,动态内存何时会被销毁
- 通过基类接受方法转发派生 UniquePtr 的右值会移动引用而不是复制
- 指针上的 For 循环:它会移动整个地址范围吗?
- 程序编译,但当分解为函数时实际上不会移动电机
- 字符和 int 连接何时会导致 seg 错误?
- 对象传递给STD ::移动,但不会移动
- 当使用 std::move 和 lambda 时,何时会发生移动
- thread.detach() 函数的左值何时会超出以下代码的范围
- 传递给协程的临时何时会被销毁?
- 在这种情况下,值是否会移动
- std::string移动构造函数真的会移动吗
- 确保"std::vector"不会移动其指针
- 何时会检查执行的类型参数
- 按值返回指针不会移动对象
- 检测窗口何时停止移动
- memmove会移动元素(就像前面的方式相同),还是一次抓住整个内存块
- 移动构造函数何时会被调用
- SetFilePointer不会失败,但也不会移动指针
- 何时会出现结构包装问题
- 我可以通过其句柄判断可等待计时器何时会触发