操作员新做什么
What does operator new do?
我试图弄清楚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;
都是未定义的行为,因为它们尚未初始化。在2
和3
(在代码方面找不到两者之间的差异)中,第一行cout << a << endl;
现在是定义的行为,因为您已经通过a = new munch;
分配了内存地址a
。但是,a->x
仍未初始化(您从未使用类似 a->x = 5;
的东西来设置它),因此cout << a->x << endl;
这两种情况下仍然是未定义的行为。
在第一种情况下,您正在读取一个未初始化的指针,这是未定义的行为(a
和a->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
每个新内容都应附带删除。
- #定义c-预处理器常量..我做错了什么
- 努力将整数转换为链表。不知道我在这里做错了什么
- 使用不同的CRT将新的C++代码与旧的(二进制)组件隔离开来的最佳方法是什么
- 我可以做些什么来消除或最小化这种将提供相同功能和行为的代码重复
- 正在解码MSVC 32位版本的程序集(作业).没有手术做什么
- c++20[[no.unique_address]]中的新功能是什么
- C++的解析器在可以区分比较和模板实例化之前会做什么?
- .h 和.cpp文件分离时出错,但仅使用 .h 文件时没有错误.我做错了什么?
- 当我们为(;;) 写作时,它做了什么?for 循环中的双分号有什么作用?
- 我的C++线程做错了什么?
- 我不知道这条线是做什么的
- 这个模板在做什么?
- 是什么让放置新调用对象的构造函数?
- 如果我真的真的想从 STL 容器继承,并且我继承构造函数并删除新运算符,会发生什么?
- "delete"在 C++ 中实际上做了什么?
- ID3D11Device::CreateBuffer在引擎盖下做什么?
- 谁能告诉我我用 getline 做错了什么 (cpp) 格式
- 操作员新做什么
- 新MinGW gcc什么都不做
- 当我做新的T[1]时会发生什么?