Безопасно ли #define NULL nullptr? - PullRequest
42 голосов
/ 25 января 2012

Я видел макрос ниже во многих самых верхних заголовочных файлах:

#define NULL 0  // C++03

Во всем коде NULL и 0 используются взаимозаменяемо. Если я изменю это на.

#define NULL nullptr  // C++11

Это вызовет какой-нибудь плохой побочный эффект? Я могу думать об единственном (хорошем) побочном эффекте, поскольку следующее использование станет плохо сформированным;

int i = NULL;

Ответы [ 6 ]

40 голосов
/ 25 января 2012

Я видел макрос ниже в самом верхнем заголовочном файле:

Вы не должны были видеть это, стандартная библиотека определяет его в <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*)

Однако, если это когда-либо имело место, оно почти наверняка было сломано.

14 голосов
/ 25 января 2012

Гораздо лучше искать и заменять NULL на nullptr по всему коду.

Это может быть синтаксически безопасно, но куда бы вы поместили #define?Это создает проблемы с организацией кода.

7 голосов
/ 25 января 2012

Нет. Вы не можете (пере) определять стандартные макросы. И если вы видите

#define NULL 0

вверху любого файла, кроме стандартного заголовка (и даже там, он должны включать в себя охранников, и, как правило, в дополнительных охранников, как хорошо), то этот файл сломан. Удалить его.

Обратите внимание, что хорошие компиляторы обычно определяют NULL с чем-то как:

#define NULL __builtin_null

, чтобы получить доступ к встроенному компилятору, который вызовет предупреждение, если оно используется в контексте без указателя.

4 голосов
/ 25 января 2012

Возможно, нет

Если у вас есть определенный формат поведения перегрузки:

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

Тогда поведение кода:

foo(NULL);

будет меняться в зависимости от того, будет ли NULL изменен на nullptr.

Конечно, есть еще один вопрос относительно того, безопасно ли писать такой код, который присутствует в этом ответе ...

4 голосов
/ 25 января 2012

Вы не должны определять его вообще, если только вы не пишете свою собственную версию <cstddef>; это, конечно, не должно быть во «многих верхних заголовочных файлах».

Если вы внедряете свою собственную стандартную библиотеку, то единственным требованием является

18.2 / 3 Макрос NULL - это константа нулевого указателя C ++, определяемая реализацией

так что либо 0, либо nullptr приемлемо, а nullptr лучше (если ваш компилятор его поддерживает) по указанной вами причине.

2 голосов
/ 25 января 2012

Хотя это может нарушить обратную совместимость со старыми материалами, которые были плохо написаны (или это, или слишком умно ...) , для вашего нового кода это не проблема.Вы должны использовать nullptr, а не NULL, где вы имеете в виду nullptr.Кроме того, вы должны использовать 0, где вы имеете в виду ноль.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...