GCC中nullptr异常行为探究:是否属于编译器Bug?
我正在学习一段刻意编写的错误程序,目前还在深入理解阶段,不想带着误解继续。
测试代码
我在测试new分配内存时遇到了意外行为,编写了如下代码进行演示:
#include <iostream> #include <new> using namespace std; int main() { // 检查内存分配失败时是否会被赋值为nullptr int i = 2000000000; // 在long类型取值范围内 int * p2 = new (nothrow) int[i]; cout << "Allocation innappropriate amount of memory and getting nullptr?" << endl << endl; cout << "Pointer address: " << p2 << " --- Value at pointer address: " << *p2 << endl << endl; if(p2) { cout << "True - Pointer address: " << p2 << " --- Value at pointer address: " << *p2 << endl << endl << endl; } else { cout << "False -Pointer address: " << p2 << " --- Value at pointer address: " << *p2 << endl << endl << endl; } // 检查GCC中nullptr的表现 int * p1 = nullptr; cout << "Assigning nullptr to pointer varialble." << endl << endl; if(p1) { cout << "True - Pointer address: " << p1 << " --- Value at pointer address: " << *p1 << endl << endl << endl; } else { cout << "False -Pointer address: " << p1 << " --- Accessing value would cause error!" << endl << endl << endl; } }
程序输出
Allocation innappropriate amount of memory and getting nullptr? Pointer address: 0x1f70783e040 --- Value at pointer address: 0 True - Pointer address: 0x1f70783e040 --- Value at pointer address: 0 Assigning nullptr to pointer varialble. False -Pointer address: 0 --- Accessing value would cause error! Process returned 0 (0x0) execution time : 0.096 s Press any key to continue.
我的疑问
我发现第二部分中,按标准无需解引用指针即可进行布尔测试,但实际结果与预期不符。请问这是对C++标准的不同解读,还是GCC的Bug?
解答
nullptr的布尔转换完全符合标准
C++标准明确规定,nullptr(类型为nullptr_t)可以隐式转换为bool,转换结果为false;任何非空指针转换为bool的结果都是true。你第二部分的代码中,p1被赋值为nullptr,所以if(p1)等价于判断static_cast<bool>(p1),结果为false,进入else分支输出对应内容,这完全符合标准,既不是GCC的Bug,也不存在标准解读差异。第一部分内存分配的行为说明
你分配了20亿个int,总内存大小为2000000000 * sizeof(int)(通常为8GB左右)。如果你的系统是64位,拥有足够的虚拟内存空间,new(nothrow)会成功分配内存,返回非空指针,此时if(p2)为true是正确的。你看到*p2的值为0,是因为new(nothrow)不会初始化分配的内存,这个0是内存中的随机残留值,并非初始化结果。如果内存分配失败,new(nothrow)才会返回nullptr,此时if(p2)会进入else分支,但你的当前环境中分配成功了,所以行为符合预期。代码中的风险点
第一部分代码存在严重问题:如果new(nothrow)真的返回nullptr,你直接解引用*p2会触发未定义行为。正确的做法是先检查指针是否非空,再进行解引用操作。
内容的提问来源于stack exchange,提问作者WackEyedWanderer

