Чем выделенный из кучи объект const будет отличаться от неконстантного? - PullRequest
11 голосов
/ 02 декабря 2011

В C ++ можно выделить объект const в куче :

const Class* object = new const Class();
const_cast<Class*>( object )->NonConstMethod(); // UB

так что попытка записи в объект будет UB.

Я не понимаю, как такой объект будет отличаться от объекта, выделенного в куче, который не объявлен const:

const Class* object = new Class();

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

Тем не менее, всякий раз, когда я использую new, компилятор должен вызывать operator new() вызов функции, и эта функция не может делать ничего другого - он просто распределяет память единообразным образом, независимо от того, был ли const в моем код.

Чем const объект, выделенный в куче, отличается от не const объекта и как возможно неопределенное поведение, если я пытаюсь изменить его?

Ответы [ 5 ]

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

Это отличается, потому что созданный объект имеет другой тип (const Class вместо просто Class), и это неопределенное поведение, потому что стандарт так говорит.

Это короткая версия.Там не должно быть причины.(если что-то, обратное верно. Не должно быть причины для чего-то, что является UB. UB является состоянием по умолчанию. Это только когда есть причина, по которой что-то становится четко определенным)

Какдля того, что это означает на практике , или если это действительно может вызвать проблемы, если вы рассматриваете объект как неконстантный, аппаратные средства вряд ли сделают что-то другое.Очевидно, что объект const не будет записан в какую-либо постоянную память (поскольку это невозможно), и страница памяти, на которой он находится, вероятно, не будет помечена как доступная только для чтения после выделения объекта.

Но компилятору разрешено предполагать , что объект является const.Таким образом, он может оптимизировать или преобразовать код таким образом, чтобы это было допустимо, если объект гарантированно не изменяется, но нарушается, если объект был изменен на полпути.аппаратное обеспечение.Const или нет const редко имеет значение на аппаратном уровне.Но это имеет значение в системе типов, и это имеет значение в том, как компилятор может преобразовать код.

Если вы сообщаете компилятору, что объект является const, то компилятор вам верит, игенерирует код в предположении, что объект является постоянным.

4 голосов
/ 02 декабря 2011

Нет никакой разницы в объекте .Существует разница в типе (времени компиляции) переменной (ей), используемой для ссылки на область памяти.

Это только семантическое трение: переменная отличается,фактическая память, используемая битами данных, является постоянным / изменчивым агностиком.

Для очень забавной и поучительной истории, описывающей подобное семантическое трение, посмотрите этот любимый на все времена ответ Эрика Липперта:

При неопределенном поведении

ЛечениеКонстантные данные неконстантным способом могут привести к неопределенному поведению, поскольку компилятору разрешено выполнять определенные оптимизации на основе знания , что переменная const не изменится 1 .Тем не менее, его изменение (например, на const_cast<>) может привести к ошибочным результатам, поскольку предположения компилятора активно отрицаются.

1 Обратите внимание, что volatile может помочь в случаях, когда переменные const могут изменяться одновременно.Вы можете видеть, как const является «локальным» не будет / не может касаться Promis, тогда как volatile говорит: 'не думайте, что это не изменится, даже еслион не записывается в этот сегмент кода '.`

1 голос
/ 02 декабря 2011

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

const больше касается отказа от компиляции кода, который модифицирует объект, чем о том, что фактически невозможно сделать какие-либо изменения.Это примечание для компилятора, которое говорит: «Не позволяйте мне пытаться изменить это по ошибке».

1 голос
/ 02 декабря 2011

С текущими компиляторами нет технической разницы. Неопределенное поведение включает в себя вещи, чудесным образом работающие.

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

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

Нет никакой разницы между постоянным и неконстантным объектом.Там нет неопределенного поведения ни в вашем примере.Какой UB вы ожидаете?Вызвав неконстантную функцию, вы получите ожидаемое от нее поведение.

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

class A {
public:
    A() : value_(0) {}
    void abuse() const { const_cast<A*>(this)->value_  = 1 ; }
    int value_;
    };

void test() {
    const A a;
    std::cout << a.value_ << std::endl;
    a.abuse() ;
    std::cout << a.value_ << std::endl;
    }

Там мы можем получить UB.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...