我在许多最顶层的头文件中看到了下面的宏:
#define NULL 0 // C++03
在所有代码中,NULL
和0
可以互换使用。如果我把它改成.
#define NULL nullptr // C++11
它会引起不良副作用吗?我能想到的唯一(好的)副作用是以下用法会变得不规范;
int i = NULL;
我在最上面的头文件中看到了下面的宏:
您不应该看到,标准库在<cstddef>
(和<stddef.h>
)中定义了它。而且,IIRC,根据标准,重新定义标准头文件定义的名称会导致未定义的行为。因此,从纯粹的标准观点来看,你不应该这么做。
我见过人们做以下事情,无论出于什么原因,他们破碎的头脑会想到:
struct X{
virtual void f() = NULL;
}
(如[错误]:"将虚拟表指针设置为NULL
")
这仅在NULL
定义为0
时有效,因为= 0
是纯虚拟函数(§9.2 [class.mem]
)的有效令牌。
也就是说,如果NULL
被正确地用作空指针常量,那么任何东西都不应该中断
然而,要注意,即使看起来使用正确,这也会改变:
void f(int){}
void f(char*){}
f(0); // calls f(int)
f(nullptr); // calls f(char*)
然而,如果真是这样的话,它几乎肯定会被打破。
更好的方法是在整个代码中搜索NULL
并用nullptr
替换。
它在语法上可能是安全的,但你会把#define
放在哪里?它会产生代码组织问题。
否。不允许(重新)定义标准宏。如果你看到
#define NULL 0
在除标准标头之外的任何文件的顶部(甚至在那里,它应在包含防护装置中,通常在附加防护装置中好吧),那么那个文件就坏了。移除它。
注意,优秀的编译器通常会用一些东西来定义NULL
类似:
#define NULL __builtin_null
,访问编译器内建,如果是在非指针上下文中使用。
您根本不应该定义它,除非您正在编写自己版本的<cstddef>
;它当然不应该出现在"许多最顶端的头文件"中。
如果您正在实现自己的标准库,那么唯一的要求就是
18.2/3宏NULL是一个实现定义的C++空指针常量
所以0
或nullptr
都是可以接受的,nullptr
更好(如果编译器支持的话)。
也许不是
如果你有一种特殊的过载行为格式:
void foo(int);
void foo(char*);
然后代码的行为:
foo(NULL);
将根据NULL是否更改为nullptr而更改。
当然,还有另一个问题是,编写这个答案中的代码是否安全。。。
虽然它可能会破坏与写得不好的旧东西的向后兼容性(要么是这样,要么过于聪明…),但对于您的新代码来说,这不是问题。应该使用nullptr
,而不是NULL
,这里的意思是nullptr
。此外,您应该使用0
来表示零。