use*_*332 4 c++ initialization undefined-behavior
以下是安全的吗?
*(new int);
我输出为0.
Jon*_*rdy 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;
这是未定义的行为(UB),因为您正在访问一个不确定的值,C++ 14显然会产生这种未定义的行为.我们可以看到,new没有初始化程序默认初始化,从草案C++ 14标准部分5.3.4 新的第17段说(强调我的未来):
如果省略new-initializer,则默认初始化对象(8.5).[注意:如果未执行初始化,则对象具有不确定的值. - 尾注]
对于int,这意味着一个不确定的值,来自8.5第7节,其中说:
默认初始化T类型的对象意味着:
- 如果T是(可能是cv限定的)类类型(第9节),则调用T的默认构造函数(12.1)(如果T没有默认构造函数或重载解析(13.3),则初始化是错误的歧义或在初始化上下文中删除或无法访问的函数中;
- 如果T是数组类型,则每个元素都是默认初始化的;
- 否则,不执行初始化.
我们可以从节中8.5看到生成不确定值是未定义的:
如果没有为对象指定初始化程序,则默认初始化该对象 .当获得具有自动或动态存储持续时间的对象的存储时,该对象具有不确定的值,并且如果没有对该对象执行初始化,则该对象保留不确定的值,直到该值被替换(5.17).[注意:具有静态或线程存储持续时间的对象是零初始化的,请参见3.6.2.- 结束注释 如果评估产生不确定的值,则行为未定义,但以下情况除外
并且所有异常都与unsigned narrow char有关,而int不是.
乔恩提出了一个有趣的例子:
int& x = *(new int); 
为什么这不是未定义的行为可能不会立即显而易见.要注意的关键点是产生值的未定义行为,但在这种情况下不会产生任何值.我们可以通过8.5.3 参考文章来看到这一点,参考文献包括参考文献的初始化,它说:
对类型"cv1 T1"的引用由类型"cv2 T2"的表达式初始化,如下所示:
- 如果引用是左值引用和初始化表达式
- 是左值(但不是位域),"cv1 T1"与"cv2 T2"引用兼容,或者
接着说:
然后在第一种情况下将引用绑定到初始化表达式lvalue [...] [注意:通常的左值到右值(4.1),数组到指针(4.2)和函数到指针(4.3) )当完成对左值的这种直接绑定时,不需要标准转换,因此被抑制. - 尾注]