使用 C++ lambda 表达式初始化类成员

Sou*_*Roy 4 c++ lambda c++11

我想std::string filePath使用 lambda 表达式初始化一个类成员 ( )。程序编译正常,但没有输出。这里有什么问题?

#include <iostream>
#include <string>

class MyString
{
  public:
  std::string filePath = [this] ()
  {
      return oneStr.append(" two");
  }();
    
  std::string oneStr;
};

int main()
{
  MyString str;
  str.oneStr = std::string(" one");
  printf("%s", str.oneStr.c_str());
}
Run Code Online (Sandbox Code Playgroud)

tes*_*08s 11

我在 Linux 5.8.6 上用 clang v10.0.1 编译了你的代码。您的代码遇到了核心转储。以下是一些日志valgrind(为了避免混淆而进行了简化):

==12170== Conditional jump or move depends on uninitialised value(s)
==12170==    at 0x49BEAFE: _M_check_length (basic_string.h:322)
==12170==    by 0x49BEAFE: std::string::append(char const*) (basic_string.h:1238)
==12170==    by 0x10944A: MyString::filePath::{lambda()#1}::operator()[abi:cxx11]() const (test.cc:9)
==12170==    by 0x109390: MyString::MyString() (test.cc:7)
==12170==    by 0x109270: main (test.cc:17)
Run Code Online (Sandbox Code Playgroud)

显然函数有问题append。事实上,你的问题是oneStr在它的初始化之前使用

根据 cppreference:

https://en.cppreference.com/w/cpp/language/constructor

列表中成员初始化器的顺序无关紧要:实际初始化顺序如下:

...

3) 然后,非静态数据成员按照类定义中的声明顺序进行初始化。

因此,在filePath被初始化之前oneStr被初始化。对 lambda 进行评估,this捕获,this->oneStr未初始化。


更改声明的顺序将修复此未定义的行为

#include <iostream>
#include <string>

class MyString
{
  public:
  std::string oneStr;
  std::string filePath = [this] ()
  {
      return oneStr.append(" two");
  }();
};

int main()
{
  MyString str;
  str.oneStr = std::string(" one");
  printf("%s", str.oneStr.c_str());
}
Run Code Online (Sandbox Code Playgroud)

但是你仍然可能没有得到预期的结果(也许 one two?)。你只会看到 one打印出来的。那是因为 oneStr 首先用 初始化"",然后附加了" two"in MyString::MyString();但最终" one"main功能中分配了之前打印。