如果你取消引用`new int`会发生什么?

时间:2014-08-20 01:09:25

标签: c++ initialization undefined-behavior

以下是否安全?

*(new int);

我的输出为0

4 个答案:

答案 0 :(得分:11)

它未定义,因为您正在读取具有不确定值的对象。表达式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;

答案 1 :(得分:7)

这是undefined behavior UB ),因为您正在访问一个不确定的值,C ++ 14显然会产生这种未定义的行为。我们可以在draft C++14 standard部分new 段落 17 中看到5.3.4没有初始化程序默认初始化 em>其中说(强调我的前进):

  

如果省略new-initializer,则默认初始化该对象   (8.5)。 [注意:如果没有执行初始化,则对象具有   不确定的价值。 - 后注]

for int 这意味着一个不确定的值,来自8.5 7 ,其中包含:

  

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

     

- 如果T是(可能是cv限定的)类类型(第9节),则调用T的默认构造函数(12.1)(和   如果T没有默认构造函数或重载分辨率(13.3)导致a初始化是错误的   歧义或在初始化上下文中删除或无法访问的函数中;;

     

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

     

- 否则,不会执行初始化。

我们可以从8.5部分看到,生成不确定值是未定义的:

  

如果没有为对象指定初始化程序,则该对象为   默认初始化即可。使用自动或自动存储对象时   获得动态存储持续时间,该对象具有不确定性   值,如果没有对该对象执行初始化,那么   对象保留不确定的值,直到替换该值   (5.17)。 [注意:具有静态或线程存储持续时间的对象是   零初始化,见3.6.2。 - 结束说明   如果评估产生了不确定的值,则行为未定义,但以下情况除外

并且所有异常都与 unsigned narrow char 有关, int 不是。

Jon提出了一个有趣的例子:

int& x = *(new int); 

为什么这不是未定义的行为可能不会立即显而易见。需要注意的关键点是生成是未定义的行为,但在这种情况下不会产生任何值。我们可以通过转到8.5.3 参考部分来看到这一点,该部分涵盖了参考文献的初始化,它说:

  

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

     
    

- 如果引用是左值引用和初始化表达式

         
      

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

引用兼容     
  

继续说:

  

然后将引用绑定到初始化表达式lvalue中   第一种情况[...] [注:通常的左值到右值(4.1),   数组到指针(4.2)和函数到指针(4.3)标准   转换不是必需的,因此被抑制,等   直接绑定到左值。 - 后注]

答案 2 :(得分:2)

计算机可能会有&#34;陷阱&#34;值int:无效值,例如校验和位,当它与预期状态不匹配时会引发硬件异常。

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

否则,不,取消引用new-expression没有任何错误或非常不寻常。以下是使用您的构造的一些奇怪但完全有效的代码:

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

答案 3 :(得分:1)

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

此代码安全,格式良好且有意义:

int *p = new int;       // ie this is a local variable (ptr) that points 
                        // to a heap-allocated block

但是,您不得取消引用指针,因为这会导致未定义的行为。 IE可能会得到0x00或0xFFFFFFFF,或指令指针(也就是英特尔上的RIP寄存器)可能会跳转到随机位置。电脑可能会崩溃。

int *p = new int;
std::cout << *p;    // Very, bad. Undefined behavior.

ValgrindASan等运行时检查程序会捕获问题,标记它并使用错误消息崩溃。

然而,初始化已分配的内存块是完全正确的:

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

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

请注意,根据标准参考,有时初始化很便宜,因此您可以执行以下操作:

// at the file scope
int global1;          // zero-initialized
int global2 = 1;      // explicitly initialized

void f()
{
    std::cout << global1;
}

这些东西进入可执行文件的部分(.bss和.data),并由OS加载程序初始化。