零初始化自动变量和动态变量规则的区别

the difference of automatic and dynamic variables rules in zero initialization

这样的代码,

#include <iostream>
 
class obj
{
public:
    int v;
};

int main(int argc, char *argv[])
{
    obj o1; 
    std::cout << o1.v << std::endl; // print 32766, indeterminate values
    obj *o2 = new obj();
    std::cout << o2->v << std::endl; // print 0,but why?

    int v1;
    std::cout << v1 << std::endl; // print 22024, indeterminate values
    int *v2 = new int;
    std::cout << *v2 << std::endl; // print 0,but why?
    return 0;
}

我知道全局或静态变量将初始化为零。
并自动执行不确定的值。
但是堆对象使用了new关键字,有没有参考解释一下?

obj *o2 = new obj(); 值初始化 意味着对象将被零初始化,因此数据成员 v 将被初始化为 0

这个可以从value initialization看出:

This is the initialization performed when an object is constructed with an empty initializer.

new T ()  (2)     

2,6) when an object with dynamic storage duration is created by a new-expression with the initializer consisting of an empty pair of parentheses or braces (since C++11);


另一方面,

int *v2 = new int; //this uses default initialization
std::cout << *v2 << std::endl; //this is undefined behavior

以上会导致未定义的行为,因为您取消引用v2并且分配的int对象未初始化,因此具有不确定的值。

未定义的行为意味着任何事情都可能发生。但是从不依赖(或根据)具有 UB 的程序的输出。程序可能会崩溃。

这个可以从default initialization看出:

This is the initialization performed when an object is constructed with no initializer.

new T     (2)     

when an object with dynamic storage duration is created by a new-expression with no initializer;

The effects of default initialization are:

  • otherwise, no initialization is performed: the objects with automatic storage duration (and their subobjects) contain indeterminate values.

来自 C++ 17 标准(11.6 初始化程序)

11 An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.

对于像 int 这样的基本类型,它意味着 zero-initialization。

所以在这个声明中

obj *o2 = new obj();

动态分配对象的数据成员v是zero-initialized。

至于这段代码

int *v2 = new int;
std::cout << *v2 << std::endl; // print 0,but why?

那么指针v2指向的对象没有初始化,下一个输出语句可以输出新对象分配的内存区中存储的任何值。

初始化规则是一团乱七八糟的记忆。因此,让我们绕过他们并强制解决这个问题:

class obj
{
public:
    int v{};
};

那里,现在 v 总是要初始化的。如果您添加一个不初始化 v 的构造函数,这甚至会起作用,因为编译器会自动添加成员初始化。


至于您的代码为何如此运行:

obj o1; 
std::cout << o1.v << std::endl; // print 32766, indeterminate values

o1 是在堆栈(或实际上是寄存器)上创建的,default initialized。其中 int 意味着没有初始化。无论堆栈上(或寄存器中)的随机数据是什么,您都会得到。

obj *o2 = new obj();
std::cout << o2->v << std::endl; // print 0,but why?

来自 C++ 17 标准(11.6 初始化程序):

11 An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.

int

Value initialization 将其设置为 0。

int v1;
std::cout << v1 << std::endl; // print 22024, indeterminate values

默认初始化,你得到随机数据。

int *v2 = new int;
std::cout << *v2 << std::endl; // print 0,but why?

默认初始化,你得到随机数据。新分配的内存恰好为 0,除非它被应用程序重用。