Назначение ссылки путем разыменования нулевого указателя

int&  fun()
{
    int * temp = NULL;
    return *temp;
}

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

int* temp = NULL:
int& temp1 = *temp;

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


person G Mann    schedule 16.07.2011    source источник
comment
Ссылки обрабатываются как указатели внутри, они просто отличаются синтаксисом, который вы используете для них. Зная, что ваше разыменование только присваивает значение указателя ссылке, что делает его ссылкой на NULL. Это не вызывает никакого доступа к памяти. Когда вы возвращаете значение по значению, разыменование приведет к доступу к памяти в 0, что почти всегда дает вам segfault.   -  person Nobody moving away from SE    schedule 16.07.2011


Ответы (5)


Разыменование нулевого указателя является неопределенным поведением.

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

По общему признанию, я собираюсь добавить эту стандартную цитату C++ в энный раз, но, похоже, это необходимо.

Что касается неопределенного поведения,

Раздел 1.3.24 стандарта C++ гласит:

Допустимое неопределенное поведение варьируется от полного игнорирования ситуации с непредсказуемыми результатами до поведения во время трансляции или выполнения программы документированным образом, характерным для среды (с выдачей или без выдачи диагностического сообщения), до прекращения трансляции или выполнения (с выдачей диагностического сообщения).

ПРИМЕЧАНИЕ.
Кроме того, просто доводим до вашего сведения:
Использование возвращаемой ссылки или указателя на локальную переменную внутри функции также является неопределённым поведением. . Вы должны выделять указатель на свободное хранилище (кучу), используя новый, а затем возвращать ссылку/указатель на него.

EDIT:
Как правильно отмечает @James McNellis в комментариях,
если возвращаемый указатель или ссылка не используются, поведение хорошо определено.

person Alok Save    schedule 16.07.2011
comment
Да, согласен с вышеупомянутым УБ. но мой вопрос заключается в том, что если разыменование указателя NULL или указателя, отличного от NULL, выполняется для присвоения этого ссылке, то выполняет ли компилятор операцию разыменования? как Int* t = NULL; Int& t1 = *t; - person G Mann; 16.07.2011
comment
@G Mann: Ссылка - это просто alias для исходного типа, которым она была инициализирована. То, как это реализовано, является деталью реализации компиляторов, и стандарт не определяет, как это должно быть реализовано. - person Alok Save; 16.07.2011
comment
Когда вы уважаете нулевой указатель, код недействителен, и компилятор может делать что угодно. Бессмысленно спрашивать, почему он что-то сделал. - person Bo Persson; 16.07.2011
comment
@Bo Persson: Увидев, что комментарии публикуют Q. Я думаю, что OP немного перепутал его, инициализировав указатель на NULL Теперь я думаю, что он / она действительно хотел знать, как компилятор обрабатывает ссылку, если она ссылается на указатель тип. - person Alok Save; 16.07.2011
comment
@ALs- хорошо. Таким образом, в этом случае, произойдет ли операция разыменования или нет, это зависит от реализации компилятором инициализации ссылки. Верно? - person G Mann; 16.07.2011
comment
@G Mann - То, что именно происходит, зависит от того, как реализована ссылка. В стандарте этого тоже не сказано, просто как должна работать ссылка. - person Bo Persson; 16.07.2011
comment
Это то, что я искал. Теперь это имеет смысл для меня. Спасибо ALs и Бо Перссон.. - person G Mann; 16.07.2011
comment
Возврат ссылки или указателя на локальную переменную внутри функции также является неопределённым поведением. Это неверно: если возвращаемый указатель или ссылка не используются, поведение определено правильно. - person James McNellis; 16.07.2011
comment
@James McNellis: Спасибо, Джеймс, что читаешь между строк! Как обычно отличный комментарий и приятно замеченный. Я изменил ответ, чтобы отразить то же самое. - person Alok Save; 16.07.2011

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

Как только выражение *temp вычислено, невозможно рассуждать о поведении программы.

person James McNellis    schedule 16.07.2011
comment
Я добавляю тот же комментарий, что и в другом посте: Да, согласен с вышеупомянутым UB. но мой вопрос заключается в том, что если разыменование указателя NULL или указателя, отличного от NULL, выполняется для присвоения этого ссылке, то выполняет ли компилятор операцию разыменования? как Int* t = NULL; Int& t1 = *t; - person G Mann; 16.07.2011
comment
Дело в том, что для большинства компиляторов во многих случаях ссылка реализуется как указатель. Кроме того, это зависит от компилятора, настроек и т.д. - person James McNellis; 16.07.2011
comment
Поправьте меня я ошибаюсь. Там, где он реализован как указатель, компилятор может не выполнять операцию разыменования. - person G Mann; 16.07.2011

Вам не разрешено разыменовывать нулевой указатель, поэтому компилятор может сгенерировать код, предполагая, что вы этого не сделаете. Если вы все равно сделаете это, компилятор может быть милым и сообщить вам об этом, но это не обязательно. Это ваша часть контракта, в которой сказано, что вы не должны этого делать.

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

person Bo Persson    schedule 16.07.2011

* Не используйте нулевой указатель, это UB. (неопределенное поведение, вы никогда не можете предположить, что оно сделает что-либо, кроме как подожжет вашу собаку и заставит вас брать грибы, что приведет к НЕВЕРОЯТНЫМ анекдотам)

Немного истории и информации о нулевых указателях в семействе Algol/C: http://en.wikipedia.org/wiki/Pointer_(computing)#Null_pointer

Примеры и последствия неопределенного поведения: http://en.wikipedia.org/wiki/Undefined_behavior#Examples_in_C< /а>

person 禪 師 無    schedule 16.07.2011

Я не уверен, что понимаю, что вы пытаетесь сделать. Разыменование ** NULL** указателя не определено.

Если вы хотите указать, что ваш метод не всегда возвращает значение, вы можете объявить его как:

логическое удовольствие (int &val);

или stl (аналогично std::map insert):

std::pair<int, bool> fun();

или повысить способ:

boost::optional<int> fun();
person dimba    schedule 16.07.2011