Когда плохой код C ++ пытается создать нулевую ссылку, как показано ниже:
int &ptr2ref(int *p){
return *p;
}
int calc(int &v){
return v*2;
}
...
int &i = ptr2ref(nullptr);
calc(i);
По крайней мере, в Visual C ++ это вылетало в операторе возврата функции calc
(режим отладки).
Тем не менее, ответ этот вопрос цитаты
8.3.2 / 1:
Ссылка должна быть инициализирована
обратитесь к действительному объекту или функции.
[Примечание: в частности, нулевая ссылка
не может существовать в четко определенном
программа, потому что единственный способ
создать такую ссылку будет
привязать его к «объекту», полученному
разыменование нулевого указателя, который
вызывает неопределенное поведение. Как
описанный в 9.6, ссылка не может
быть привязанным непосредственно к битовому полю. ]
1,9 / 4:
Некоторые другие операции описаны
в этом международном стандарте, как
неопределенный (например, эффект
разыменование нулевого указателя)
Если я правильно понимаю, стандарт говорит, что как только создается нулевая ссылка, поведение программы становится неопределенным. Так что, если компилятор предназначен для генерации полезной отладочной информации он должен потерпеть крах при работе ptr2ref
в приведенном выше примере, так как там, где создается нулевая ссылка (и происходит отсылка).
Я что-то пропустил? Есть ли какие-либо проблемы, останавливает компилятор генерировать такой код как минимум в режиме отладки?
Неопределенное поведение
Я знаю, что люди будут утверждать, что «неопределенный» означает примерно все. Мой аргумент, учитывая тот факт, что стандарт не указывал, как долго простой int main(){}
потребуется для компиляции, никто не примет время компиляции больше одного дня. Так что проблема в том, варианты реализации, не сам стандарт. Я процитировал стандарт здесь просто сказать, что сбой на ptr2ref
Это вариант.
Более того, в режиме отладки уже происходит много дополнительных проверок, например, стек всегда проверялся на предмет повреждения, прежде чем вернуться из функции. Сравните с теми, которые я не думаю, что добавить относительно простую проверку будет слишком много в режим отладки.
«Неопределенное поведение» не означает «Сбой сейчас».
Это определено в стандарте C ++, раздел 1.3.24
Поведение, к которому данный международный стандарт не предъявляет никаких требований
[Примечание: при этом Международном
Стандарт опускает любое явное определение поведения или когда программа
использует ошибочную конструкцию или ошибочные данные. Допустимый неопределенный
поведение варьируется от полного игнорирования ситуации с
непредсказуемые результаты, ведущие себя во время перевода или программы
выполнение задокументированной характеристикой среды
(с выдачей диагностического сообщения или без него), до прекращения
перевод или исполнение (с выдачей диагностического
сообщение). Многие ошибочные программные конструкции не порождают неопределенных
поведение; они должны быть диагностированы.
«Неопределенное поведение» означает, что может случиться что угодно, и компилятор не обязан делать что-то конкретное. В этом случае здесь ничего катастрофического не происходит при разыменовании нулевого указателя, он просто переводит программу в недопустимое состояние, создавая нулевую ссылку. Что вызывает проблемы позже.
Конечно, было бы желательно, если бы ошибка могла быть обнаружена ранее, но единственный способ сделать это — добавить компилятору явные проверки нулевого указателя ко всем операциям разыменования, что приведет только к потере производительности при хорошем поведении (без нулевых указателей). используется неправильно) программа. Поскольку разыменование нулевого указателя обычно быстро приводит к сбоям в любом случае, это, вероятно, не считается оправданным даже в режиме отладки.
Если я правильно понимаю, стандарт говорит, что как только создается нулевая ссылка, поведение программы становится неопределенным.
Да, это правильно. Текст, который гарантирует это:
Ссылка должна быть инициализирована для ссылки на действительный объект или функцию.
Результат разыменования нулевого указателя, безусловно, не является допустимым объектом или функцией.
Вы также цитируете следующий текст:
[Примечание: в частности, пустая ссылка не может существовать в четко определенной программе, потому что единственный способ создать такую ссылку — это привязать ее к «объекту», полученному путем разыменования нулевого указателя, что вызывает неопределенное поведение. Как описано в 9.6, ссылка не может быть привязана непосредственно к битовому полю. ]
Тем не менее, «Примечание» означает, что это ненормативный, то есть текст должен быть пояснительным, но фактически не является частью стандартной спецификации. И, что несколько удивительно, оказывается, что Стандарт на самом деле нигде не говорит (что мне известно), что *p
вызывает неопределенное поведение.
Это делает скажем, что преобразование lvalue в prvalue на *p
вызывает неопределенное поведение, но также говорит, что это преобразование не выполняется в случае привязки ссылки.
Это пришло в выпуск 1102 .