Как бы выделяемый кучей объект const отличался от неконстантного?

В С++ можно выделить объект 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() invocation, и эта функция не может делать ничего другого - она ​​просто распределяет память единообразно, независимо от того, был ли const в моем код.

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

Ответ 1

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

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

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

В Undefined Поведение

Обработка const-данных неконстантным способом может привести к Undefined Поведению, поскольку компилятору разрешено выполнять определенные оптимизации на основе знания о том, что константная переменная не изменится 1. Изменение его без изменений (например, const_cast<>) может привести к несходным результатам, поскольку предположения компилятора активно отрицаются.

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

Ответ 2

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

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

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

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

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

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

Ответ 3

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

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

Ответ 4

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

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

Ответ 5

Нет никакой разницы между const и non-const объектом. В вашем примере нет поведения undefined. Что вы ожидаете от UB? Вызывая функцию non-const, вы получите поведение, которое вы ожидаете от нее.

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

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.