2012-01-25 14 views
40

Widziałem poniżej makro w wielu najwyższych plików nagłówkowych:Czy można bezpiecznie #define NULL nullptr?

#define NULL 0 // C++03 

W całym kodzie NULL i 0 są używane zamiennie. Jeśli zmienię to na.

#define NULL nullptr // C++11 

Czy spowoduje to niepożądane skutki uboczne? Mogę myśleć o jedynym (dobrym) efekcie ubocznym, ponieważ następujące użycie będzie źle sformułowane;

int i = NULL; 

Odpowiedz

39

Widziałem poniżej makro w najwyższej pliku nagłówka:

Nie powinieneś zauważyć, że średnia biblioteka definiuje ją w <cstddef> (i <stddef.h>). I, IIRC, zgodnie ze standardem, redefiniowanie nazw zdefiniowanych przez standardowe pliki nagłówkowe powoduje niezdefiniowane zachowanie. Więc z czysto standardowego punktu widzenia nie powinieneś tego robić.


Widziałem ludzi, wykonaj następujące czynności, niezależnie od przyczyny ich zepsuty umysł myśl:

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

(jak w [nieprawidłowo]: "ustawić kursor wirtualny stół do NULL")

jest ważny tylko jeśli NULL jest zdefiniowana jako 0, ponieważ = 0 jest ważne token funkcji czystej wirtualnego (§9.2 [class.mem]).

Powiedział, jeśli NULL był poprawnie stosowany jako null pointer stałą, wtedy nic nie należy łamać.

Jednak uwaga, że ​​nawet jeśli pozornie są stosowane prawidłowo, to się zmieni:

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

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

Jednak jeśli kiedykolwiek był przypadek, to było prawie na pewno uszkodzony zapas.

+0

"Nie powinieneś tego widzieć". Dlaczego tak się czujesz? Widziałem nawet dziwne makro, takie jak '#define NULL (void *) (0)' w kodzie produkcyjnym dla DSP dla WCDMA L1. – iammilind

+6

Czy 'virtual void f() = 0L;' legal? Ponieważ '#define NULL 0L' z pewnością jest zgodną implementacją. –

+6

@iammilind: Nie powinieneś, ponieważ 'NULL' jest już zdefiniowany przez standard. – Xeo

14

Znacznie lepiej jest, aby wyszukać i zastąpić NULL z nullptr całym kodzie.

Może to być syntaktycznie bezpieczne, ale gdzie umieścić #define? Tworzy problemy organizacji kodu.

+10

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

+7

uważam kod, który wymaga pewnych Flagi kompilatora nie są przenośne. – spraff

+0

Cóż, myślę, że nie możemy już -Dowindows, ani nic takiego, i musimy przepisać cały nasz kod, aby przenieść go na inną platformę ... –

2

Chociaż może to przełamać kompatybilność wsteczną ze starszymi materiałami, które zostały źle napisane (albo to, albo zbyt sprytnie ...), dla twojego nowego kodu, to nie jest problem. Powinieneś użyć nullptr, a nie NULL, gdzie masz na myśli nullptr. Ponadto powinieneś używać 0, gdzie masz na myśli zero.

+3

Pamiętaj, że dobrze napisane starsze pliki nie będą również używać 'nullptr', ponieważ zostały dodane do języka zaledwie kilka miesięcy temu. –

+1

@Mike: dobrze napisane starsze rzeczy mogą mieć coś w rodzaju '#define NULLPTR NULL', jednak można je zmienić na' #define NULLPTR nullptr' podczas kompilacji jako C++ 11. A potem wszystkie instancje 'NULLPTR' w kodzie usunięto, gdy jesteś pewien, że już nigdy nie będziesz musiał kompilować go jako C++ 03. –

+1

@SteveJessop Poważnie? Mam na myśli, może teraz, że wiemy o nullptr, że makro NULLPTR miałoby sens, ale stary kod (* przed dodaniem * nullptr został dodany do standardu), który wydaje się ... mało prawdopodobny. – luiscubal

4

Nie powinieneś definiować go w ogóle, chyba że piszesz własną wersję <cstddef>; to na pewno nie powinno być w "wielu najwyższych plikach nagłówkowych".

Jeśli wdrożenie własnej biblioteki standardowej, wówczas jedynym wymogiem jest

18,2/3 makro NULL jest C realizacja zdefiniowane ++ zerowy wskaźnik stały

więc albo 0 lub nullptr jest dopuszczalne, i nullptr jest lepszy (jeśli twój kompilator obsługuje go) z tego powodu.

7

Nie. Nie można (ponownie) definiować standardowych makr. A jeśli zobaczysz

#define NULL 0 

na górze każdego pliku inny niż standardowy nagłówek (a nawet nie powinno być m.in. strażników, a zazwyczaj w dodatkowych strażników jako również), a następnie, że plik jest uszkodzony . Usunąć to.

Należy pamiętać, że dobre kompilatory zwykle definiują NULL coś jak:

#define NULL __builtin_null 

, aby uzyskać dostęp do polecenie wbudowane kompilatora, który wywoła ostrzeżenie, jeśli jest używany w kontekście non-pointer.

+0

Może to dlatego został na nowo zdefiniowany: leniwy sposób na odstraszanie ostrzeżeń ... –

4

Maybe Not

Jeśli masz konkretny format zachowań przeciążenia:

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

Wtedy zachowanie kodu:

foo(NULL); 

będzie się zmieniać w zależności od tego, czy jest NULL zmieniono na nullptr lub nie.

Oczywiście, istnieje jeszcze jedno pytanie, czy jest to bezpieczne, aby napisać taki kod jak jest obecny w tej odpowiedzi ...

Powiązane problemy