LINUX.ORG.RU

c++ Null vs nullptr

 


0

2

Добрый день, вчера пытался разобраться в чем преимущество (конкретно, а не в виде абстрактных понятий типа ООП и прочая эзотерика) nullptr против NULL. Ничего внятного (для простых инженеров, а не всяких там страуструпов) не нашел, кроме синтетического примера

void foo(int *) {
    cout<<"foo (int *)";
}
void foo(int) {
   cout<<"foo (int);
}

foo(NULL);
foo(nullptr);
вывод
foo(int)
foo(int *)
Но этого что-то мало и вроде я такое раз в год вызываю, может кто-нибудь покажет доступные, бытовые примеры когда nullptr лучше и удобней чем NULL.


Но этого что-то мало и вроде я такое раз в год вызываю

Так можно про многие правила из стандарта сказать, типа я это почти не использую, а потому не нужно.

seiken ★★★★★
()
Ответ на: комментарий от da17

NULL это просто 0, ещё и определённый макросом, т.е. компилятор получит просто 0 в этом куске кода, некоторые конструкции аля auto не поймут что именно ты хотел использовать число или указатель

sparks ★★★
()

Effective Modern C++ Майерса.
Item 8: Prefer nullptr to 0 and NULL.

Показано развитие приведённого тобою примера для случая когда такие перегрузки за шаблонами скрыты.

mkam
()

nullptr нельзя по ошибке присвоить переменной, не являющейся указателем, с NULL такое скомпилируется и может потом привести к многочасовой отладке

annulen ★★★★★
()

На будущее: когда тебе говорят что NULL это легаси и нужно пользоваться nullptr, тебе нужно просто это сделать а не задаваться бесполезными вопросами.

Если же тебе неймётся, все ответы есть на cppreference. NULL - это implementation-defined макрос который может в зависимости от реализации раскрываться в 0 или nullptr, поэтому вопрос сводится к тому почему нельзя использовать 0 (или, что эквивалентно, макрос который может в него раскрыться). Потому что это нарушает типобезопасность - 0 можно передать в функцию принимающую int, или сравнить с int’ом. Если ты сравниваешь NULL с int’ом, или передаёшь в качестве int’а - это явная ошибка, но в этом случае компилятор её не отловит. У nullptr таких проблем нет. Кроме того, он может участвовать в перегрузках (https://en.cppreference.com/w/cpp/types/nullptr_t).

slovazap ★★★★★
()
Ответ на: комментарий от slovazap

сравниваю NULL с int

#include <iostream>
#include <string>
class Keker{
    };
int main()
{
    Keker *kek = new Keker;

    delete kek;   
    kek = NULL;
    int k = 0;
    if (kek == k)
        std::cout<<"lol!"<<std::endl;
}
Компилятор ругается In function 'int main()': 12:16: error: ISO C++ forbids comparison between pointer and integer [-fpermissive]

da17
() автор топика
Ответ на: комментарий от Gvidon

Я прочитал пример https://en.cppreference.com/w/cpp/types/nullptr_t т.е. если я все правильно понял, nullptr помогает явно указать, что должна вызываться ф-ия принимающая указатель и если у программиста функция, принимающая foo(int), а он где-то в дебрях кода передает ей нулевой указатель путем foo(NULL), то возможно он ошибся и nullptr от таких косяков уберегает, т.е. если даже программист забудет, чего принимает ф-ия, компилятор его поправит при nullptr, чего не будет при NULL?

da17
() автор топика
Ответ на: комментарий от Gvidon

Дальше не читал

да я пошутил, а то иногда напишут вместо пояснения «НАРУШАЕТ ПРИНЦИПЫ ООП» и гадай, что оно там нарушает

da17
() автор топика

История примерно такая:
1) В С++ запретили неявное приведение void* к любому другому указателю, что в С разрешено. Внезапно, отломался код

int* foo = NULL;

т.к. NULL всегда определялся как (void*)0.
2) Не унывая, в С++ решили эту проблему переиспользованием константы 0, что привело к вот такой вот радости (примерно):
#ifdef __cplusplus
#define NULL 0
#else
#define NULL (void*)0
#endif

Что, в свою очередь, начало весело стрелять при перегрузках и в шаблонах.
3) Компиляторы от такой весёлой жизни начали заводить свои нестандартные «нулевые указатели», чтобы с этим адом хоть как-то бороться. Например __null в gcc.
4) Пункт 3) узаконили в стандарте как nullptr

Всё это время сишники смотрят на плюсовиков как на стадо дебилов, пишут свой родной NULL и в ус не дуют.

Gvidon ★★★★
()
Ответ на: комментарий от da17

И что вы хотели сказать этим примером? К NULL vs. nullptr он вообще никакого отношения не имеет.

slovazap ★★★★★
()

Типобезопасность.

В чистом Си у тебя ведь перегрузки функций нет? Вот там это в ногу не выстрелит. А в костылях выстрелит и будет неприятно.

Вот и пиши nullptr, чтобы избежать двусмысленности.

Deleted
()
Ответ на: комментарий от da17

А пример можно?

Например такой: #include <cstdlib>

int main()
{
        char str[] = "hello";
        char* p = str;
        /*
        что-то делаем со строкой
        */
        p = 0;
}
То есть мы работаем со строкой, теперь захотели ограничить строку на текущем символе, и вместо
*p = '\0';
написали просто
p = 0;
Какой-то пример с массивом строк и присваиванием нуля, вместо '\0', был в одном из разборов PVS-studio какого-то опенсурс проекта, так что несмотря на то что пример искусственный, что-то подобное есть и в реальных проектах.

Но в gcc/clang есть полезное предупреждение

-Wzero-as-null-pointer-constant

fsb4000 ★★★★★
()
Ответ на: комментарий от annulen

Но сломает туеву хучу существующего кода

Забавно, но оно уже в стандарте с C++11 (provided cppreference не врет): https://en.cppreference.com/w/cpp/types/NULL

an integer literal with value zero, or a prvalue of type std::nullptr_t (since C++11)

Т.е. любишь кататься (С++11 и новее) люби и саночки возить (рефакторить).

KennyMinigun ★★★★★
()
Ответ на: комментарий от KennyMinigun

Это разве может что-то сломать? Кроме уже сломанного кода

anonymous
()
Ответ на: комментарий от KennyMinigun

В стандарте много, что написано.

А вот одна из реальностей:

mingw-w64, gcc 8.2.0

#ifndef NULL
#ifdef __cplusplus
#ifndef _WIN64
#define NULL 0
#else
#define NULL 0LL
#endif  /* W64 */
#else
#define NULL ((void *)0)
#endif
#endif

fsb4000 ★★★★★
()
Последнее исправление: fsb4000 (всего исправлений: 1)
Ответ на: комментарий от fsb4000

В стандарте много, что написано.

А небо синее.

А вот одна из реальностей:

Вполне соответствует стандарту.

KennyMinigun ★★★★★
()
Последнее исправление: KennyMinigun (всего исправлений: 1)

Дали им няшную растишечку - не хочу, хочу спорить о сортах NULL и nullptr.

Pacmu3ka
()

Деды говорили, что нужно писать так:

foo((int*)NULL);
Так же и мы поступать будем. Все это верно и для функций с переменным числом аргументов.

anonymous
()
Ответ на: комментарий от annulen

Страуструп в http://www.stroustrup.com/N1488-nullptr.pdf (классный номер пропозала) утверждает, что в gcc с 98-го года (gcc 2.8.0) #define NULL __null чтобы было возможным выдавать предупреждения при преобразовании к целочисленному нулю.

Проверять я это конечно не буду.

utf8nowhere ★★★
()
Ответ на: комментарий от slovazap

На будущее: когда тебе говорят что NULL это легаси и нужно пользоваться nullptr, тебе нужно просто это сделать а не задаваться бесполезными вопросами.

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

i-rinat ★★★★★
()
Ответ на: комментарий от da17

это не компилятор а кусок говна,который слепливает из говна говно которое потом через раз работает. Если уже пользуешься ms, то минимум msvs 17 и с опциями /permissive- /Za

invy ★★★★★
()
Последнее исправление: invy (всего исправлений: 1)

Но этого что-то мало и вроде я такое раз в год вызываю, может кто-нибудь покажет доступные, бытовые примеры когда nullptr лучше и удобней чем NULL

Шифт не нужно зажимать.

theNamelessOne ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.