操作员新做什么

What does operator new do?

本文关键字:什么 新做 操作员      更新时间:2023-10-16

我试图弄清楚new是如何工作的:

#include <iostream>
using namespace std;
struct munch{
    int x;
};
int main(){
    munch *a;
    //1
    cout << a << endl;
    cout << a->x << endl;
    //1
    cout << endl;
    //2
    a= new munch;
    cout << a << endl;
    cout << a->x << endl;
    //2
    cout << endl;
    //3
    a= new munch;
    cout << a << endl;
    cout << a->x << endl;
    //3
}

1、2 和 3 有什么区别?为什么operator new提供了构造新位置的指针,但不更改a->x的值?但是在调用new的第一个实例之前,它的值与调用new一次后的值不同?

1中,你已经声明了一个指向munch的指针,但还没有初始化它。因此,cout << a << endl;cout << a->x << endl;都是未定义的行为,因为它们尚未初始化。在23(在代码方面找不到两者之间的差异)中,第一行cout << a << endl;现在是定义的行为,因为您已经通过a = new munch;分配了内存地址a。但是,a->x仍未初始化(您从未使用类似 a->x = 5; 的东西来设置它),因此cout << a->x << endl;这两种情况下仍然是未定义的行为。

在第一种情况下,您正在读取一个未初始化的指针,这是未定义的行为(aa->x都是未定义的)。

在另外两个示例中,重要的是munch是普通旧数据。这意味着new munch不会初始化新分配的结构的字段。因此,阅读a->x也会导致未定义的行为。

C++这一点,您可以向munch添加一个构造函数,该构造函数将初始化x并使示例 2 和 3 定义良好。

[1] 是未定义的行为,因为它试图取消引用未初始化的指针。

[2] 和 [3] 是相同的,可能会导致未定义的行为,尽管至少您会在结构中获得字段的垃圾值。

更多关于 [2] 和 [3] 的标准说:

C 1999 标准在 6.7.8 10 中说:"如果未显式初始化具有自动存储持续时间的对象,则其值不确定。

此外,如果 lvalue 指定了一个自动存储持续时间的对象,该对象本可以使用寄存器存储类声明(从未获取其地址),并且该对象未初始化(未使用初始值设定项声明,并且在使用之前未对其执行任何赋值),则行为是未定义的。

首先,让我们澄清一下你的语义。

请注意,语言中既有 new 表达式,也有运算符 new

定义了各种形式的operator new,例如放置的、不可抛出的全局的和可替换的全局的。

新表达式包括调用其中一个分配函数,然后执行指示的任何初始化。
如果第二部分失败,也会调用相应的反初始化函数。

那么,让我们来看看你有什么:

在一种情况下,仅读取未初始化的非静态(因此不确定)指针就是未定义的行为。

在情况 2 和 3 中,由于 munch 是 POD 类型,因此 new-expression 不会导致构造函数调用,这意味着所有成员都保持未初始化状态,因此读取munch::x为 UB。

当你声明一个变量struct munch时,编译器所做的是,它只是获取大小相当于sizeof(munch)的内存块,并为其分配一个你给出的名称。

但是在指针声明的情况下,编译器只是为内存位置命名,并且在显式指定之前不会分配任何内存(使用new运算符)。

例如:

munch *a;

此语句将简单地将名称a分配给内存位置。因此,cout<<a将打印该内存地址。

当你这样做cout<<a->x它会给你运行时错误,因为你没有分配空间。所以你现在没有任何价值。

//阿拉伯数字

首先,将给出a指向的新内存位置。并且内存将分配给new运算符。struct内的变量将具有默认值,这些默认值已在分配的内存位置存在。

因此,当您执行cout<<a时,它将打印a的新位置。当你做cout<<a->x时,它现在会给出一些随机值。如果你一次又一次地编译和运行程序,你每次可能会得到不同的值。

/

/3

就像案例#2一样,同样的事情也会发生。首先,将选择新的内存位置,a将指向该位置。然后,您的结果将被打印,但由于内存位置不同,这些值可能与情况#2不同。

因为x的值是一个垃圾值,因为你没有在任何地方初始化它。a的第一个值也是垃圾,你也没有在任何地方指出它。

new运算符从操作系统请求内存段并调用类构造函数,返回指向该内存的指针并将其地址存储在变量中。

由于munch没有构造函数,因此它永远不会初始化x

所有的代码都有未定义的行为,所以你永远不应该那样做,使用munch结构和动态内存分配的正确方法是

munch *a;
a = new munch;
a->x = SOME_INITIAL_VALUE;
std::cout << "address of a : " << a << std::endl;
std::cout << "value of a->x: " << a->x << std::endl;

或者向结构中添加构造函数,您可以在其中初始化x

struct munch 
{
    public:
        munch(int initial_x = SOME_INITIAL_VALUE) : x(initial_x) {}
        int x;
};
munch *a;
a = new munch;
std::cout << "address of a : " << a << std::endl;
std::cout << "value of a->x: " << a->x << std::endl;

new 运算符为堆上的实例分配内存并返回指针。 对于您的代码,1. 在堆栈上分配一个项目。 2 和 3 在堆上分配项目。 当我运行您提供的代码时,我在所有 3 个实例(CodeLite/MingGW)中都获得了不同的 x 值:

0x417d7e

1528349827

0x8f6bd8

12

0x8f6be8

14

每个新内容都应附带删除。