如果你解引用' new int '会发生什么?

What happens if you dereference `new int`?

本文关键字:什么 int 如果 new 引用      更新时间:2023-10-16

以下内容安全吗?

*(new int);

我得到的输出是0 .

这是未定义的,因为你正在读取一个具有不确定值的对象。表达式new int()使用零初始化,保证零值,而new int(没有括号)使用默认初始化,给您一个不确定的值。这实际上相当于说:

int x;              // not initialised
cout << x << 'n';  // undefined value

但是,由于您立即解引用了指向您刚刚分配的对象的指针,并且没有将指针存储在任何地方,这就构成了内存泄漏。

注意,这种表达式的存在并不一定使程序病态;这是一个完全有效的程序,因为它在读取对象之前设置了对象的值:

int& x = *(new int);  // x is an alias for a nameless new int of undefined value
x = 42;
cout << x << 'n';
delete &x;

这是未定义的行为(UB),因为你正在访问一个不确定的值,c++ 14清楚地使这种未定义的行为。我们可以看到,没有初始化的new默认初始化的,从c++ 14标准草案5.3.4 New段落17说(强调我的未来):

如果省略new-initializer,则默认初始化对象(8.5)。[注:如果没有初始化,对象有一个。不确定的值。-end note]

for int这意味着一个不确定的值,来自8.57,其中说:

默认初始化T类型的对象意味着:

-如果T是(可能是cv限定的)类类型(第9条),则调用T的默认构造函数(12.1)(and)如果T没有默认构造函数,或者重载解析(13.3)导致错误,则初始化是错误的歧义(或在初始化上下文中被删除或不可访问的函数中);

—如果T是数组类型,则每个元素默认初始化;

- ,否则不进行初始化。

我们可以从8.5节看到,产生一个不确定的值是未定义的:

如果没有为对象指定初始化式,则该对象为 default-initialized 。当存储对象具有自动或获取动态存储时长时,对象具有不确定值value,如果没有对对象进行初始化,则对象保留一个不确定的值,直到该值被替换(5.17)。[注:具有静态或线程存储时间的对象是零初始化,参见3.6.2。-结束提示如果计算产生了一个不确定的值,则该行为是未定义的,除了以下情况

和所有异常都与unsigned窄字符有关,而int则不是。

Jon举了一个有趣的例子:

int& x = *(new int); 

可能不是很明显为什么这不是未定义的行为。需要注意的关键点是,生成是未定义的行为,但在这种情况下没有生成任何值。我们可以通过8.5.3 References小节看到这一点,该小节涵盖了引用的初始化,它说:

对类型"cv1 T1"的引用由类型"cv2 T2"的表达式初始化,如下所示:

—如果引用是左值引用,且初始化表达式

-是左值(但不是位域)," cv1 T1 "与" cv2 T2 "或

是引用兼容的

,接着说:

则将引用绑定到中的初始化表达式lvalue第一个案例……[注:通常的左值到右值(4.1),数组到指针(4.2)和函数到指针(4.3)标准在这种情况下,不需要转换,因此被抑制完成对左值的直接绑定。-end note]

有可能计算机有int的"陷阱"值:无效值,例如校验和位在与预期状态不匹配时引发硬件异常。

通常,未初始化的值会导致未定义的行为。先初始化

否则,不,解引用new-expression并没有什么错误或真正不寻常的。下面是一些奇怪的,但完全有效的代码使用您的结构:

int & ir = * ( new int ) = 0;
…
delete & ir;

首先,Shafik Yaghmour在他的回答中提到了《标准》。这是最好的、完整的、权威的答案。尽管如此,让我试着给你们一些具体的例子来说明上述几点。

这段代码是安全的,格式良好且有意义的:

int *p = new int;       // ie this is a local variable (ptr) that points 
                        // to a heap-allocated block
但是,不能对指针解引用,因为这会导致未定义的行为。IE可能会得到0x00或0xFFFFFFFF,或者指令指针(也就是Intel上的RIP寄存器)可能跳转到一个随机位置。电脑可能会死机。
int *p = new int;
std::cout << *p;    // Very, bad. Undefined behavior.

运行时检查器,如Valgrind和ASan将捕捉到这个问题,标记它,并以一个漂亮的错误消息崩溃。

但是,初始化您分配的内存块是完全可以的:

int *p = new int;
*p = 0;

背景信息:这种编写规范的特殊方式对性能非常有用,因为实现替代方法的成本非常高。

注意,根据标准参考,有时初始化是便宜的,所以你可以这样做:

// at the file scope
int global1;          // zero-initialized
int global2 = 1;      // explicitly initialized
void f()
{
    std::cout << global1;
}

这些东西进入可执行文件的部分()。