1

以下代码不会将结构字符串成员初始化为相同的值。

#include <string>
#include <iostream>

struct S
{
    std::string s1;
    std::string s2;
    S(std::string const& s) : s1{s}{}
    S(int i) : S([&]{
        s2 = std::to_string(i);
        return std::to_string(i);
    }())
    {}
};

int main()
{
    S s{123};
    std::cout << s.s1 << "|" << s.s2;

    return 0;
}

我在 gcc(尝试了不同的版本)和123|通过 Wandbox 的 clang(也有不同的版本)中遇到了分段错误。

我遇到读取访问冲突 Visual Studio 15.9.16

谢谢你。

4

2 回答 2

6

您给构造函数的参数(即 lambda)不能访问内部成员,因为它们还没有被构造。

这应该有效:

struct S
{
    std::string s1;
    std::string s2;
    S(std::string const& s) : s1{s}{}
    S(int i)
      : S(std::to_string(i))
    {
        s2 = s1;
    }
};
于 2019-09-20T09:10:02.930 回答
1

检查一个未初始化的对象是一个 UB,在这种情况下,它被这个字符串遮住了:

       s2 = std::to_string(i);

这是对存储在位置的对象operator=的调用。那时它还没有初始化。我假设你可以通过初始化来修复它,但是在初始化列表中的构造函数调用之前是不可能的。std::strings2s2

即使您以错误的顺序编写该部分,您也无法更改创建顺序。s2总是在 之后初始化s1,都在构造函数调用之后但在进入其主体之前完成。因此顺序如下所示:

  1. S(int)使用参数初始化调用ctor i
  2. 创建 lambda 对象,捕获thisi
  3. 调用 lambda 的 operator()
  4. 调用存储在位置的operator=对象std::strings2
  5. 的制作std::string
  6. 参考创建的字符串,委托S(std::string)带有参数的 ctor 调用。s
  7. s1用值初始化s
  8. 默认初始化s2

项目符号 4. 和 8. 发生的顺序是不合法的,更糟糕​​的是,由于实施,它可能不会产生错误,因此 gcc 版本可能会将该数据写入内存的某个随机区域。MSVC,至少在调试版本中,可能会生成一些诊断代码,因为标准没有为这种情况定义程序行为。

于 2019-09-20T09:17:10.717 回答