42

我在许多最顶层的头文件中看到了下面的宏:

#define NULL 0  // C++03

在所有的代码中,NULL0可以互换使用。如果我将其更改为。

#define NULL nullptr  // C++11

会不会有什么不好的副作用?我能想到的唯一(好的)副作用是以下用法会变得不正确;

int i = NULL;
4

6 回答 6

40

我在最顶层的头文件中看到了下面的宏:

您不应该看到,标准库在<cstddef>(and <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*)

但是,如果是这样的话,无论如何它几乎肯定是坏了。

于 2012-01-25T13:28:50.610 回答
15

更好的是在整个代码中搜索和NULL替换。nullptr

它在语法上可能是安全的,但你会把#define? 它会产生代码组织问题。

于 2012-01-25T13:26:36.550 回答
7

不,您不能(重新)定义标准宏。如果你看到

#define NULL 0

在除标准头文件之外的任何文件的顶部(即使在那里,它也应该在包含保护中,通常也在附加保护中),然后该文件被破坏。去掉它。

请注意,好的编译器通常会定义NULL如下:

#define NULL __builtin_null

, 访问内置编译器,如果在非指针上下文中使用它会触发警告。

于 2012-01-25T13:42:38.117 回答
4

您根本不应该定义它,除非您正在编写自己的<cstddef>;版本。它当然不应该出现在“许多最顶层的头文件”中。

如果您正在实现自己的标准库,那么唯一的要求是

18.2/3 宏 NULL 是实现定义的 C++ 空指针常量

所以要么0ornullptr是可以接受的,并且nullptr更好(如果你的编译器支持它)你给出的原因。

于 2012-01-25T13:34:41.470 回答
4

也许不吧

如果您有特定格式的重载行为:

void foo(int);
void foo(char*);

然后代码的行为:

foo(NULL);

将根据 NULL 是否更改为 nullptr 而更改。

当然,还有另一个问题是编写此答案中存在的代码是否安全……

于 2012-01-25T14:20:02.957 回答
2

虽然它可能会破坏与写得不好(或者过于聪明......)的旧东西的向后兼容性,但对于您的新代码来说,这不是问题。你应该使用nullptr,而不是NULL你的意思nullptr。此外,您应该使用0您的意思为零的地方。

于 2012-01-25T13:29:04.557 回答