Czy bezpiecznie jest sprawdzić wskaźnik, że nie jest NULL
, pisząc po prostu, if(pointer)
czy muszę go używać if(pointer != NULL)
?
c++
pointers
if-statement
null
null-pointer
danijar
źródło
źródło
0
lubnullptr
. (NULL
jest C'ismem i wymaga dołączenia pliku nagłówkowego.)NULL
w C ++ od tego momentu, ponieważNULL
jest to makro zależne od implementacji, które może powodować niejednoznaczne zachowania.Odpowiedzi:
Możesz; wskaźnik zerowy jest niejawnie konwertowany na wartość logiczną fałsz, podczas gdy wskaźniki inne niż null są konwertowane na wartość true. Ze standardu C ++ 11, sekcja dotycząca konwersji logicznych:
źródło
Tak, mogłeś.
Jest to część standardowej konwersji C ++, która mieści się w klauzuli konwersji Boolean :
§ 4.12 Konwersje boolowskie
źródło
Tak, możesz. W rzeczywistości wolę używać,
if(pointer)
ponieważ łatwiej jest czytać i pisać, gdy się do tego przyzwyczaisz.Zwróć również uwagę, że wprowadzono C ++ 11,
nullptr
który jest preferowany w stosunku doNULL
.źródło
if(som_integer)
vs,if(some_integer != 0)
ponieważ liczby całkowite również nie są wartościami logicznymi, prawda? Wolę unikać0
lubNULL
w oświadczeniu „jeśli”.if (pointer)
siebie, aleif (ptr != nullptr)
wydaje mi się to całkowicie uzasadnione. Z drugiej strony, gdybym zobaczył kogoś w moim zespole, który napisałif (some_integer)
, kazałbym mu to zmienićif (some_integer != 0)
. Nie będę jednak udawać, że to nie jest względnie arbitralna preferencja z mojej strony - po prostu wolę nie traktować tak samo wskaźników i liczb całkowitych.if(isReady)
if(filePtr)
if(serviceNo)
? Celowe tworzenie złych nazw zmiennych nie ma w tym przypadku większego znaczenia. W każdym razie zrozumiałem już twój punkt widzenia i zrozumiałem, ale mogę nalegać na używanie mojego własnego stylu kodowania, OK?Odpowiedź na pytanie, ale chciałbym dodać swoje punkty.
Zawsze będę wolał
if(pointer)
zamiastif(pointer != NULL)
iif(!pointer)
zamiastif(pointer == NULL)
:Mniejsze szanse na napisanie błędnego kodu, przypuśćmy, że jeśli błędnie wpisałem operator sprawdzania równości,
==
z którym=
if(pointer == NULL)
można się pomylić,if(pointer = NULL)
więc będę tego unikać, najlepiej po prostuif(pointer)
.( W jednej odpowiedzi zasugerowałem również stan Yody , ale to inna sprawa)
Podobnie za
while (node != NULL && node->data == key)
to po prostu napiszę,while (node && node->data == key)
że jest to dla mnie bardziej oczywiste (pokazuje to za pomocą zwarcia).źródło
(boolean expression)? true : false
jest całkowicie bezcelowe. Wyrażenie zwraca albo dotrue
albo dofalse
; to, co mówisz, to „jeśli to prawda, daj mi prawdę, jeśli to fałsz, daj mi fałsz”. Krótko mówiąc: jest to całkowicie równoważne z samym wyrażeniem logicznym. Zauważ, żenode == NULL
jest to wyrażenie boolowskie. Przy okazji, twoje dwie implementacje zwracają dokładnie przeciwne do siebie. Albo chcesz!=
w pierwszym, albo tylko!
w drugim.=
zamiast nich==
jest tworzenie zmiennych,const
gdy tylko jest to możliwe. Na przykład, możesz zdefiniować swoją funkcję jakoisEmnpy(node* const head) { ... }
, a wtedy kompilator odmówi jej skompilowania, jeśli przypadkowo napiszesznode = NULL
zamiastnode == NULL
. Oczywiście działa to tylko w przypadku zmiennych, których naprawdę nie trzeba zmieniać.T* get() const
zamiast tegooperator T*() const
unikać niejawnych konwersji. Mają jednak plikoperator bool() const
.Jawne sprawdzenie wartości NULL może dać kompilatorowi wskazówkę dotyczącą tego, co próbujesz zrobić, ergo prowadząc do mniejszej podatności na błędy.
źródło
Tak, możesz. Możliwość niejawnego porównywania wartości z zerami została odziedziczona z języka C i jest dostępna we wszystkich wersjach C ++. Możesz również użyć
if (!pointer)
do sprawdzenia wskaźników dla NULL.źródło
Odpowiednie przypadki użycia dla wskaźników o wartości null to
Dynamiczne rzuty. Rzutowanie wskaźnika klasy bazowej na konkretną klasę pochodną (coś, czego należy ponownie spróbować uniknąć, ale czasami może to okazać się konieczne) zawsze kończy się sukcesem, ale powoduje wyświetlenie wskaźnika o wartości null, jeśli klasa pochodna nie pasuje. Jednym ze sposobów sprawdzenia tego jest
(lub najlepiej
auto derived_ptr = ...
). To jest złe, ponieważ pozostawia (prawdopodobnie nieprawidłowy, tj. Zerowy) wskaźnik pochodny pozaif
zasięgiem bloku zabezpieczającego . Nie jest to konieczne, ponieważ C ++ pozwala na wprowadzenie zmiennych binarnych konwertowalnych wewnątrzif
-condition :który jest nie tylko krótszy i bezpieczny w zakresie, ale jest też znacznie bardziej przejrzysty w swoim celu: kiedy sprawdzasz wartość null w oddzielnym warunku if, czytelnik zastanawia się, „ok, więc
derived_ptr
nie może być tutaj zero… cóż, dlaczego to jest zerowe? ” Podczas gdy wersja jednowierszowa mówi bardzo wyraźnie: „jeśli możesz bezpiecznie przesyłaćbase_ptr
doDerived*
, użyj go do ...”.To samo działa równie dobrze w przypadku każdej innej operacji, która może spowodować niepowodzenie, która zwraca wskaźnik, chociaż IMO generalnie powinno się tego unikać: lepiej jest użyć czegoś takiego
boost::optional
jak „kontener” dla wyników operacji, które mogą zakończyć się niepowodzeniem, zamiast wskaźników.Tak więc, jeśli główny przypadek użycia wskaźników zerowych powinien być zawsze zapisywany w odmianie stylu implicit-cast, powiedziałbym, że ze względu na spójność dobrze jest zawsze używać tego stylu, tj. Byłbym zwolennikiem
if(ptr)
ponadif(ptr!=nullptr)
.Obawiam się, że muszę zakończyć reklamą:
if(auto bla = ...)
składnia jest właściwie tylko nieco kłopotliwym przybliżeniem rzeczywistego rozwiązania takich problemów: dopasowywania wzorców . Dlaczego miałbyś najpierw wymusić jakąś akcję (na przykład rzucenie wskaźnika), a następnie rozważyć, że może wystąpić awaria ... To znaczy, to śmieszne, prawda? To tak, jakbyś miał coś do jedzenia i chciał zrobić zupę. Podajesz go asystentowi, który ma wycisnąć sok, jeśli jest to miękkie warzywo. Nie patrzysz na to najpierw. Kiedy masz ziemniaka, nadal dajesz go swojemu asystentowi, ale oni uderzają go z powrotem w twarz z notatką o niepowodzeniu. Ach, konieczne programowanie!Znacznie lepiej: rozważ od razu wszystkie przypadki, które możesz napotkać. Następnie działaj odpowiednio. Haskell:
Haskell ma również specjalne narzędzia, gdy istnieje naprawdę poważna możliwość awarii (a także do całej masy innych rzeczy): monady. Ale to nie jest miejsce na ich wyjaśnianie.
⟨/ogłoszenie⟩
źródło
if(ptr)
raczej używać niżif(ptr != nullptr)
, na co można powiedzieć dużo więcej.tak oczywiście! w rzeczywistości pisanie if (wskaźnik) jest wygodniejszym sposobem pisania niż if (wskaźnik! = NULL), ponieważ: 1. jest łatwe do debugowania 2. łatwe do zrozumienia 3. jeśli przypadkowo zdefiniowana jest wartość NULL, wtedy również kod nie ulegnie awarii
źródło
Tak. Właściwie powinieneś. Jeśli zastanawiasz się, czy powoduje to błąd segmentacji , tak nie jest.
źródło
Ponieważ inni odpowiedzieli już dobrze, oba są wymienne.
Niemniej jednak warto wspomnieć, że może zaistnieć przypadek, w którym możesz chcieć użyć wyraźnego oświadczenia, tj
pointer != NULL
.Zobacz też https://stackoverflow.com/a/60891279/2463963
źródło
Tak, zawsze możesz to zrobić, ponieważ warunek „JEŻELI” ocenia się tylko wtedy, gdy warunek wewnątrz niego spełnia się. C nie ma logicznego typu zwracanego i dlatego zwraca wartość różną od zera, gdy warunek jest prawdziwy, a zwraca 0, gdy warunek w „JEŻELI” okaże się fałszywy. Wartością niezerową zwracaną domyślnie jest 1. Tak więc oba sposoby pisania kodu są poprawne, podczas gdy ja zawsze będę preferował drugi.
źródło
Zasadniczo myślę, że jeśli wyrażenie „if” można ponownie zapisać jako
taki, że nie powoduje ŻADNYCH OSTRZEŻEŃ, TO powinien być preferowanym stylem dla wyrażenia if . (Wiem, że otrzymuję ostrzeżenia, gdy przypiszę starą C
BOOL
(#define BOOL int
) do C ++bool
, nie mówiąc już o wskaźnikach.)źródło
„Czy to jest bezpieczne…?” to pytanie o standard językowy i generowany kod.
„Czy to dobra praktyka?” jest pytaniem o to, jak dobrze zdanie jest rozumiane przez dowolnego człowieka, który je odczytuje. Jeśli zadajesz to pytanie, sugeruje to, że „bezpieczna” wersja jest mniej jasna dla przyszłych czytelników i pisarzy.
źródło