立即计算的 lambda 的 C++ 范围规则

标签 c++ lambda

当我运行此 C++ 代码时:

#include <iostream>
#include <vector>
using namespace std;

int main()
{
  vector<int> vec = [&] ()
  {
    cout<<"pre vec.size() = "<< vec.size() <<endl;
    vector<int> retval = {};
    for(int i = 0; i < 10; ++i)
      vec.push_back(i); // I typed "vec", not "retval"
    
    cout<<"vec.size() = "<< vec.size() <<endl;
    cout<<"retval.size() = "<< retval.size() <<endl;
    return retval;
  }();
  
  cout<< vec.size() <<endl;
}
我得到输出:
pre vec.size() = 34354494244
vec.size() = 10
retval.size() = 10
10
在 lambda 内部, vec 似乎首先未初始化(请参阅大小)。为什么 push_backing 不会导致(valgrind)错误?
循环后,vec 的大小为 10,可以。但是为什么 retval 的大小也已经是 10(而不是 0)了?
由于我在 lambda 中填充了 vec,但返回了空的 retval,为什么 vec 在评估后的大小为 10(而不是 0)?
我尝试了 g++ 9.3.0 和 clang++ 10.0.0 并获得了行为。

最佳答案

尝试对您的程序进行小幅调整。添加打印两个 vector 地址的语句:

#include <iostream>
#include <vector>
using namespace std;

int main()
{
  vector<int> vec = [&] ()
  {
    cout<<"pre vec.size() = "<< vec.size() <<endl;
    vector<int> retval = {};

    std::cout << &retval << " = " << &vec << std::endl;
    for(int i = 0; i < 10; ++i)
      vec.push_back(i); // I typed "vec", not "retval"

    cout<<"vec.size() = "<< vec.size() <<endl;
    cout<<"retval.size() = "<< retval.size() <<endl;
    return retval;
  }();

  cout<< vec.size() <<endl;
}
gcc 显示 两者的地址 retvalvec !这是named return value optimization的结果,这是允许的。这就是 valgrind 无法检测到这种未定义行为的原因。未定义的行为意味着“任何事情都可能发生”,包括程序按预期工作。这就是这里发生的事情:vec的实际构造发生在 retval被构造,并且从 lambda 返回的结果没有发生复制。载体已经构建好了。
但是请注意,命名返回值优化是可选的,不需要实现。您不能依赖每个编译器都以这种方式工作,而将未定义行为的原始问题放在一边。

关于立即计算的 lambda 的 C++ 范围规则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64171181/

相关文章:

C++ GetAsyncKeyState 在控制台窗口中不工作

c++ - vector 碰撞

c++ - 如何在 Unicode 字符串中查找不能作为单词一部分的字符?

c++ - Qt connect 无法识别 lambda 表达式

LISP 如何将 lambda 函数关联到名称/符号以便稍后调用它?

c++ - MFC 应用程序 : How to add a set of controls to an single document application?

c++ - cURL c++ 和 gunzip

c# 在 Lambda 表达式中声明变量

c++ - std::unordered_map - 使用 Lambda 专门化 KeyEqual

ruby - 在 Ruby 中,如果我在循环内声明一个 lambda 函数,它会在每次迭代后正确清理吗?