为什么部分初始化 class 然后调用委托 ctor 失败?
Why partially initializing a class and then invoking delegating ctor fails?
以下代码不会将结构字符串成员初始化为相同的值。
#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
谢谢。
你给构造函数(即 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;
}
};
检查未初始化的对象是一个 UB,在这种情况下它被这个字符串遮盖了:
s2 = std::to_string(i);
这是对 std::string
的 operator=
的调用,用于存储在 s2
位置的对象。
那时它还没有初始化。我假设您可以通过初始化 s2
来修复它,但是在初始化列表中调用构造函数之前不可能这样做。
您不能更改创建顺序,即使您以错误的顺序编写该部分。 s2
总是在 s1
之后初始化,两者都在构造函数调用之后但在进入其主体之前完成。因此顺序看起来像:
- 调用 ctor
S(int)
并初始化参数 i
;
- 创建 lambda 对象,捕获
this
和 i
- 调用 lambda 的 operator()
- 为存储在
s2
位置的对象调用 std::string
的 operator=
- 创建
std::string
- 引用创建的字符串,使用参数
s
委托 ctor S(std::string)
的调用。
s1
的初始化值为 s
s2
的默认初始化
项目符号 4. 和 8. 按顺序发生,这是不合法的,更糟糕的是,由于实现,它可能不会产生错误,因此 gcc 版本可能将该数据写入内存的某个随机区域。 MSVC,至少在调试版本中,可能会生成一些诊断代码,因为标准没有为这种情况定义程序行为。
以下代码不会将结构字符串成员初始化为相同的值。
#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
谢谢。
你给构造函数(即 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;
}
};
检查未初始化的对象是一个 UB,在这种情况下它被这个字符串遮盖了:
s2 = std::to_string(i);
这是对 std::string
的 operator=
的调用,用于存储在 s2
位置的对象。
那时它还没有初始化。我假设您可以通过初始化 s2
来修复它,但是在初始化列表中调用构造函数之前不可能这样做。
您不能更改创建顺序,即使您以错误的顺序编写该部分。 s2
总是在 s1
之后初始化,两者都在构造函数调用之后但在进入其主体之前完成。因此顺序看起来像:
- 调用 ctor
S(int)
并初始化参数i
; - 创建 lambda 对象,捕获
this
和i
- 调用 lambda 的 operator()
- 为存储在
s2
位置的对象调用 - 创建
std::string
- 引用创建的字符串,使用参数
s
委托 ctorS(std::string)
的调用。 s1
的初始化值为s
s2
的默认初始化
std::string
的 operator=
项目符号 4. 和 8. 按顺序发生,这是不合法的,更糟糕的是,由于实现,它可能不会产生错误,因此 gcc 版本可能将该数据写入内存的某个随机区域。 MSVC,至少在调试版本中,可能会生成一些诊断代码,因为标准没有为这种情况定义程序行为。