const приведенный к глобальному var и программа потерпела крах (C ++) - PullRequest
2 голосов
/ 29 декабря 2011
int main()
{
    const int maxint=100;//The program will crash if this line is put outside the main
    int &msg=const_cast<int&>(maxint);  
    msg=200;  
    cout<<"max:"<<msg<<endl; 
    return 0;
}

Функция будет работать нормально, если 'const int maxint = 100;'определение помещается в основную функцию, но происходит сбой и появляется сообщение об ошибке «Нарушение прав доступа», если оно помещено снаружи.

Кто-то говорит, что это какое-то «неопределенное поведение», и я хочу знать точный ответ и какя могу безопасно использовать константный актер?

Ответы [ 3 ]

9 голосов
/ 29 декабря 2011

Они верны, это неопределённое поведение. Вам не разрешено изменять значение переменной const, что представляет собой опасность отбрасывания const сущности чего-либо: вам лучше знать это не совсем const.

Компилятор, видя, что maxint равен const и должен никогда никогда не изменяться, даже не должен давать ему адрес. Он может просто заменить все варианты использования maxint на 100, если сочтет нужным. Также, как указывает Matteo Italia, он может просто поместить константу в часть памяти, предназначенную только для чтения, что, вероятно, и происходит с вами. Вот почему его изменение приводит к неопределенному поведению.

Единственный способ безопасно исключить const из переменной - это если переменная на самом деле не const, но квалификатор const был добавлен в переменную, отличную от const, например:

int f(const int& x) {
    int& nonconst = const_cast<int&>(x);

    ++nonconst;
}

int blah = 523;

f(blah); // this is safe

const int constblah = 123;

f(constblah); // this is undefined behaviour

Подумайте об этом примере, который прекрасно компилируется:

int f(const int& x) {
    int& nonconst = const_cast<int&>(x);

    ++nonconst;
}

int main() {
    f(4); // incrementing a number literal???
}

Вы можете видеть, как использование const_cast довольно опасно, потому что нет никакого способа узнать, является ли переменная изначально const или нет. Вам следует избегать использования const_cast, когда это возможно (с функциями, просто не принимая параметры const).

5 голосов
/ 29 декабря 2011

Изменение объекта const (за исключением изменяемых членов) приводит к неопределенному поведению (из стандарта C ++ 03):

7.1.5.1 / 4 "CV-квалификаторы"

За исключением того, что любой член класса, объявленный mutable (7.1.1), может быть изменен, любая попытка изменить объект const в течение его времени жизни (3.8) приводит к в неопределенном поведении.

Вышеуказанное неопределенное поведение специально вызывается в разделе стандарта на const_cast:

5.2.11 / 7 "Const cast"

[Примечание: в зависимости от типа объекта, операция записи через указатель, lvalue или указатель на элемент данных, полученный в результате const_cast, который отбрасывает const-qualifier68) может привести к неопределенному поведение (7.1.5.1). ]

Итак, если у вас есть const указатель или ссылка на объект, который на самом деле не const, вам разрешено писать в этот объект (отбрасывая константу), но не если объект действительно const.

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

0 голосов
/ 29 декабря 2011

Вам разрешено отбрасывать только константу объекта, который известен , а не как const.Например, интерфейс может передавать объекты с помощью указателя const или ссылки const, но вы передали объект, который не является const и хотите / нужно его изменить.В этом случае может быть правильным отбросить константность.

С другой стороны, отбрасывание константности объекта, который был const полностью, может привести к серьезным неприятностям: при доступе к этому объекту,в частности, при записи в нее система может вызывать всевозможные странные вещи: поведение не определено (стандартом C ++), а в конкретной системе это может вызвать, например, нарушение доступа (поскольку адрес объекта устроен так, чтобынаходиться в области только для чтения.)

Обратите внимание, что, несмотря на другой ответ, я видел, что const объектам необходимо получить назначенный адрес, если адрес когда-либо был получен и использован каким-либо образом.В вашем коде выражение const_cast<int&>(maxint) по существу получает адрес вашей константы int, который, очевидно, хранится в области памяти, помеченной как доступная только для чтения.Интересным аспектом вашего фрагмента кода является то, что он , по-видимому, работает, особенно при включении оптимизации: код достаточно прост, чтобы компилятор мог сказать, что измененное местоположение на самом деле не используется и не 'на самом деле попытаться изменить место в памяти!В этом случае нарушения доступа не сообщается.Это, по-видимому, тот случай, когда константа объявлена ​​внутри функции (хотя константа также может находиться в стеке, который обычно не может быть помечен как доступный только для чтения).Другим потенциальным результатом вашего кода (независимо от того, объявлена ​​ли константа внутри функции или нет) является то, что она фактически изменяется и иногда читается как 100, а в других контекстах (которые так или иначе включают адрес) как 200.

...