gpt4 book ai didi

c++11 - 为什么委托(delegate)给默认构造函数不为零初始化成员变量

转载 作者:行者123 更新时间:2023-12-04 12:45:10 24 4
gpt4 key购买 nike

#include <string>

struct T1 {
int _mem1;
int _mem2;
T1() = default;
T1(int mem2) : T1() { _mem2 = mem2; }
};
T1 getT1() { return T1(); }
T1 getT1(int mem2) { return T1(mem2); }
int main() {
volatile T1 a = T1();
std::printf("a._mem1=%d a._mem2=%d\n", a._mem1, a._mem2);
volatile T1 b = T1(1);
std::printf("b._mem1=%d b._mem2=%d\n", b._mem1, b._mem2);
// Temporarily disable
if (false) {
volatile T1 c = getT1();
std::printf("c._mem1=%d c._mem2=%d\n", c._mem1, c._mem2);
volatile T1 d = getT1(1);
std::printf("d._mem1=%d d._mem2=%d\n", d._mem1, d._mem2);
}
}

当我用 gcc5.4 编译它时,我得到以下输出:
g++ -std=c++11 -O3 test.cpp -o test && ./test
a._mem1=0 a._mem2=0
b._mem1=382685824 b._mem2=1

为什么委托(delegate)给默认构造函数的用户定义构造函数无法将 b 的 _mem1 设置为零,但是 a哪个使用默认构造函数是零初始化的?

Valgrind 也证实了这一点:
==12579== Conditional jump or move depends on uninitialised value(s)
==12579== at 0x4E87CE2: vfprintf (vfprintf.c:1631)
==12579== by 0x4E8F898: printf (printf.c:33)
==12579== by 0x4005F3: main (in test)

如果我将 if(false) 更改为 if(true)

然后输出如你所料
a._mem1=0 a._mem2=0
b._mem1=0 b._mem2=1
c._mem1=0 c._mem2=0
d._mem1=0 d._mem2=1

编译器在做什么?

最佳答案

简答 :对于普通类型,“默认构造”的两种不同形式导致两种不同的初始化:

  • T a;在这种情况下,对象是默认初始化的。它的值是未确定的,未定义的行为很快就会发生(这是如何初始化 b.mem1 以及为什么 valgrind 检测到错误。)
  • T a=T();在这种情况下,对象被值初始化并且其整个内存被归零(这就是 a.mem1a.mem2 发生的情况)

  • 长答案 : 实际上, T1 的默认构造函数不是 a.mem1 零初始化的原因。 a已先零初始化,但未初始化 b因为标准的单一规则不适用于 b的初始化器。

    定义 volatile a=T()原因 a成为 value-initialized (1)。 struct T1user-provided默认构造函数 (2)。对于这样的结构,整个对象是 zero-initialized正如 C++11 标准 [dcl.init]/7.2 的这条规则所述:

    if T is a (possibly cv-qualified) non-union class type without a user-provided constructor, then the object is zero-initialized and, if T's implicitly-declared default constructor is non-trivial, that constructor is called.



    C++11 和 C++17 之间存在细微差别,导致定义 volatile b=T(1)在 C++11 中是未定义的行为,但在 C++17 中不是。在 C++11 中, b通过复制对象类型 T1 进行初始化由表达式 T(1) 初始化.此复制结构评估 T(1).mem1这是一个未确定的值。这是 forbidden .在 c++17 中, b由纯右值表达式 T(1) 直接初始化.
    printf 中对这个未确定值的评估也是独立于 c++ 标准的未定义行为。这就是为什么 valgrind 会提示以及为什么您在更改 if (true) 时会看到不一致的输出。至 if (false) .

    (1) 严格来说 a是从 c++11 中的值初始化对象构造的副本

    (2) T1 的默认构造函数不是用户提供的,因为它在第一个声明中被定义为默认的

    关于c++11 - 为什么委托(delegate)给默认构造函数不为零初始化成员变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51282507/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com