【问题标题】:Repeatedly moving a variable from lambda that has been move captured反复从 lambda 中移动一个已被移动捕获的变量
【发布时间】:2018-09-25 16:19:20
【问题描述】:

我有以下测试代码:

#include <iostream>
#include <string>

void printValue(std::string&& val)
{
    std::cout << "Got value: " << val << "\n";
}

int main() {

    std::string testValue = "Test Value";

    auto lambda = [testValue = std::move(testValue)]() mutable
    {
        printValue(std::move(testValue));
    };

    lambda();
    lambda();
    lambda();
}

我得到了结果:

Got value: Test Value
Got value: Test Value
Got value: Test Value

这是一个有效的假设,即从 lambda 中移动已捕获的对象将始终具有将其移动到 lambda 中的初始状态,或者这只是对象处于“有效但未指定”的伪影状态”?

【问题讨论】:

  • std::move 给予许可移动。它不做任何其他事情。收到这种“移动”值的客户可能会选择从中移动,也可能不会。在您的示例中,printValue 选择不从val 移动。

标签: c++ c++11 lambda c++14 move-semantics


【解决方案1】:

std::move 不执行移动操作;它只是将参数转换为右值。对于您的代码,printValue 通过右值引用获取参数,因此参数 testValue 将通过引用传递。但不对其执行移动操作,则testValue 不会被更改。

如果你把val改成传值,那么testValue这个参数会被移动到val中,或者你也可以像这样显式添加移动操作

void printValue(std::string&& val)
{
    std::cout << "Got value: " << val << "\n";
    std::string x = std::move(val);            // perform move operation on val
}

两者都会导致移动操作执行 3 次,然后你会得到不同的结果,例如与clang,

Got value: Test Value
Got value: 
Got value: 

PS:正如你所说,从移动构造后的对象将处于有效但未指定的状态。尽管大多数实现都这样做,但标准不保证上述行为。

【讨论】:

  • 如果 printValue 按值获取字符串 gcc 也会给出与下面显示的结果相同的结果。
  • @super 是的,效果一样; testValue 被移动到参数val 中。
  • 在 move-constructed-from 时,std::string 是指定清除其来源,还是留下未指定的内容?
  • @Yakk 它将处于未指定状态。
  • @Yakk 在常见实现中允许有效但未指定的状态与空状态还有一个(微小的)潜在性能优势,因为它允许为 SSO(小字符串优化)保持原始字符串不变。但是,就目前而言,似乎所有实现都清除了源字符串,即使它很小。
猜你喜欢
  • 2015-12-05
  • 2012-01-28
  • 2021-04-12
  • 1970-01-01
  • 2018-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-06
相关资源
最近更新 更多