const_cast и UB

$ 5.2.11 / 7 - "[Примечание: в зависимости от типа объекта операция записи через указатель, lvalue или указатель на член данных, являющаяся результатом const_cast, отбрасывающего квалификатор const68) может производить неопределенное поведение (7.1.5.1).] "

Формулировки этого раздела (C ++ 03) меня удивляют. Удивительны две вещи.

а) Во-первых, использование слова «может». Почему это «может»? Другие места в Стандарте дают очень точные сведения о неопределенном поведении.

б) Почему отказ от константности изначально константного объекта не сразу приводит к «неопределенному поведению». Почему для запуска UB требуется запись?


person Chubsdad    schedule 28.10.2010    source источник
comment
Я отсылаю читателей к ответу Kaz Dragon - 7.1.5.1/4, который, как мне кажется, поясняет, что это не UB, если исходный объект не был объявлен const. Формулировка этого бита в Стандарте до некоторой степени неоднозначна. Но есть намеренно написанный пример кода, процитированный на одном дыхании, указывающий на то, что определена запись через const_casted ref / ptr к изначально не-const объекту, что я считаю более авторитетным, чем абзац с зависимостью и может в нем. ;)   -  person underscore_d    schedule 23.02.2016


Ответы (4)


а) Во-первых, использование слова «может». Почему это «может»? Другие места в Стандарте очень точно определяют поведение undefined.

Не вдавайтесь в подробности использования слова может здесь. Дело в том, что отказ от константности в этом случае вызывает неопределенное поведение.

Стандарт C ++ часто использует слова «может» или «мог бы», например:

1.3.12: Неопределенное поведение может также ожидаться, если в этом международном стандарте отсутствует описание какого-либо явного определения поведения.

Акцент мой. По сути, в стандарте используется слово «может», например, «разрешено» .

б) Почему отказ от константности изначально константного объекта не сразу приводит к «неопределенному поведению». Почему для запуска UB требуется запись?

Запись запускает UB, потому что на определенных платформах объекты const могут храниться в постоянной памяти.

person Charles Salvia    schedule 28.10.2010

Насколько я понимаю, это будет UB, только если рассматриваемый объект в основном является константным объектом, а не константным указателем или ссылкой на объект, который изначально не был константным.

Идея состоит в том, что данные, которые по своей сути являются константными, могут быть загружены в часть памяти, доступную только для чтения, и запись в нее просто не сработает. Однако он гарантированно будет работать правильно, если рассматриваемый объект фундаментально изменен.

Ex:

const int  x = 4;
const int *y = x;

*const_cast<int*>(x) = 3; // UB - the pointed-to object may 
                          // be in read-only memory or whatever.

int        a = 7;
const int *b = a;

*const_cast<int*>(b) = 6; // Not UB - the pointed-to object is 
                          // fundamentally mutable.

Комментарий ниже, потому что код в комментариях выглядит ужасно:

В §7.1. 5.1 / 4 стандарта приведен следующий пример:

int i = 2;
const int * cip; // pointer to const int
cip = &i;        // OK: cv-qualified access path to unqualified
...
int* ip;
ip = const_cast <int *>( cip ); // cast needed to convert const int* to int*
*ip = 4;                        // defined: *ip points to i, a non-const object

Так что это специально разрешено.

person Kaz Dragon    schedule 28.10.2010
comment
Я не согласен. Стандарт C ++. §7.1.​5.1/4 says Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const object during its lifetime (3.8) results in undefined behavior Любая попытка! - person Alexey Malistov; 12.11.2010
comment
@Alexey - Теперь посмотрите на пример для §7.1. 5.1 / 4 именно там, где вы процитировали. Это специально позволяет этот случай. Я добавил код к ответу выше, потому что здесь он выглядел ужасно. - person Kaz Dragon; 12.11.2010
comment
+1 за 7.1.5.1/4. Я думаю, что формулировка, процитированная в вопросе, в лучшем случае плохо написана, в худшем - опасно противоречива. Но я беру специально написанный пример кода, в котором утверждается, что этот четко определен как более авторитетный, чем абзац с зависимостью и может в нем. - person underscore_d; 23.02.2016

Что касается вашего первого вопроса, если что-то может вызывать неопределенное поведение, это не делает его менее неопределенным.

Что касается второй части, я полагаю, это из соображений совместимости. Например, в C нет (или не было до C99) ключевого слова const, поэтому, если вы хотите передать константный объект функции C, константу придется отбросить. Таким образом, стандарт C ++ определяет, что это разрешено до тех пор, пока не выполняется запись. Если функция C доступна только для чтения, константу можно безопасно отбросить.

Даже в C ++ непоследовательная или неполная константная корректность тоже довольно распространена. Поэтому иногда мы сталкиваемся с ситуациями, когда нам нужно отбросить константу, чтобы передать константный объект функции, которая не изменяет свой аргумент, а принимает его неконстантным.

person jalf    schedule 28.10.2010
comment
Чего ждать? Я почти уверен, что у C89 есть const. См. Раздел 3.5.3 Квалификаторы типа на странице flash-gordon.me.uk/ansi.c. txt - person Charles Salvia; 28.10.2010
comment
В C89 есть const, но многие старые и / или дрянные, но полезные API C (и даже C ++) его все равно не используют. - person Steve M; 28.10.2010
comment
О, странно. Интересно, почему я подумал, что это не так? Я исправился. :) - person jalf; 28.10.2010

Я считаю, что это потому, что объект const может быть сохранен в постоянной памяти. Таким образом, запись в него может иметь множество различных эффектов: сбой программы, ошибка сегментации или отсутствие эффекта.

person Didier Trosset    schedule 28.10.2010