2012-01-25 1 views
40

J'ai vu ci-dessous macro dans de nombreux fichiers d'en-tête les plus hautes:Est-il prudent de # définir NULL nullptr?

#define NULL 0 // C++03 

Dans tout le code, NULL et 0 sont utilisés de façon interchangeable. Si je le change.

#define NULL nullptr // C++11 

Y aura-t-il un effet indésirable? Je peux penser au seul (bon) effet secondaire car l'usage suivant deviendra mal formé;

int i = NULL; 

Répondre

39

J'ai vu ci-dessous macro dans le fichier d'en-tête le plus élevé:

Vous ne devriez pas avoir vu que, la bibliothèque standard définit en <cstddef> (et <stddef.h>). Et, IIRC, selon la norme, la redéfinition des noms définis par les fichiers d'en-tête standard entraîne un comportement indéfini. Donc, d'un point de vue purement normatif, vous ne devriez pas faire cela.


J'ai vu des gens faire ce qui suit, pour une raison quelconque leur esprit brisé la pensée de:

struct X{ 
    virtual void f() = NULL; 
} 

(Comme dans [mal]: "mettre le pointeur de table virtuelle NULL")

Ceci n'est valide que si NULL est défini comme 0, car = 0 est le jeton valide pour les fonctions purement virtuelles (§9.2 [class.mem]).

Cela dit, si NULL était correctement utilisé comme un pointeur NULL constante, alors rien ne devrait se briser.

Cependant, méfiez-vous que, même si apparemment utilisé correctement, cela va changer:

void f(int){} 
void f(char*){} 

f(0); // calls f(int) 
f(nullptr); // calls f(char*) 

Cependant, si cela soit le cas, il a été presque certainement cassé de toute façon.

+0

'Vous ne devriez pas avoir vu ça'. Pourquoi tu te sens si bien? J'ai même vu une macro étrange, '#define NULL (void *) (0)' dans un code de production pour DSP pour WCDMA L1. – iammilind

+6

Est-ce que 'virtual void f() = 0L;' légal? Parce que '#define NULL 0L' est certainement une implémentation conforme. –

+6

@iammilind: Vous ne devriez pas, car 'NULL' est déjà défini par le standard. – Xeo

14

Il vaut bien mieux est de rechercher et remplacer NULL avec nullptr à travers le code.

Il peut être syntaxiquement sûr, mais où placeriez-vous le #define? Cela crée des problèmes d'organisation de code.

+10

'g ++ -DNULL = nullptr ...' :) – Xeo

+7

Je considère le code qui exige certains les drapeaux du compilateur doivent être non portables. – spraff

+0

Eh bien, je suppose que nous ne pouvons pas -DWindows, ou quoi que ce soit de ce genre, et nous devons réécrire tout notre code pour le porter vers une autre plateforme ... –

2

Alors que cela pourrait casser la compatibilité ascendante avec des choses plus anciennes qui ont été mal écrites (que ce soit, ou trop intelligent ...), pour votre nouveau code, c'est un non-problème. Vous devez utiliser nullptr, et non NULL, où vous voulez dire nullptr. En outre, vous devez utiliser 0 où vous voulez dire zéro.

+3

Gardez à l'esprit que les anciens éléments bien écrits n'utiliseront pas non plus nullptr, puisqu'il n'a été ajouté à la langue que quelques mois plus tôt. –

+1

@Mike: des choses plus anciennes bien écrites pourraient avoir quelque chose comme '#define NULLPTR NULL', qui peut être changé en' #define NULLPTR nullptr' lors de la compilation en C++ 11. Et puis toutes les instances de 'NULLPTR' dans le code supprimé une fois que vous êtes sûr que vous ne devrez plus jamais le compiler en C++ 03. –

+1

@SteveJessop Sérieusement? Je veux dire, peut-être maintenant que nous savons à propos de nullptr que la macro NULLPTR aurait du sens, mais l'ancien code (* avant * nullptr a été ajouté à la norme) ayant cela semble .. improbable. – luiscubal

4

Vous ne devriez pas le définir du tout, sauf si vous écrivez votre propre version de <cstddef>; il ne devrait certainement pas être dans "de nombreux fichiers d'en-tête topmost".

Si vous implémentez votre propre bibliothèque standard, la seule exigence est

18,2/3 La NULL macro est un pointeur C++ null défini par l'implémentation constante

donc soit 0 ou nullptr est acceptable, et nullptr est préférable (si votre compilateur le supporte) pour la raison que vous donnez.

7

Non. Vous n'êtes pas autorisé à (re) définir des macros standard. Et si vous voyez

#define NULL 0 

en haut d'un fichier autre qu'un en-tête standard (et même là, il devrait être inclure des gardes, et généralement en gardes supplémentaires bien), alors que le fichier est cassé . Retirez-le.

Notez que les bons compilateurs définissent généralement NULL avec quelque chose comme :

#define NULL __builtin_null 

, pour accéder à un compilateur qui builtin déclenchera un avertissement si elle est utilisé dans un contexte non-pointeur.

+0

Peut-être que c'est la raison pour laquelle il a été redéfini: façon paresseuse de chasser les avertissements ... –

4

Peut-être pas

Si vous avez un format particulier du comportement de surcharge:

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

Ensuite, le comportement du code:

foo(NULL); 

changera selon que NULL est changé en nullptr ou non.

Bien sûr, il y a une autre question de savoir s'il est sûr d'écrire du code, comme est présent dans cette réponse ...

Questions connexes