Может ли объект, выделенный для кучи, быть const в С++?
В С++ объект, выделенный для стека, может быть объявлен const
:
const Class object;
после этого попытка вызова неконстантного метода для такого объекта - это поведение undefined:
const_cast<Class*>( &object )->NonConstMethod(); //UB
Может ли выделенный объект с кучей const
с теми же последствиями? Я имею в виду, возможно ли следующее:
const Class* object = new Class();
const_cast<Class*>( object )->NonConstMethod(); // can this be UB?
также является undefined поведением?
Ответы
Ответ 1
Да. Это законно для создания и уничтожения объекта кучи const
. Как и в случае с другими объектами const
, результаты управления им как объектом не const
(например, через const_cast
указателя или ссылки) приводят к поведению undefined.
struct C
{
C();
~C();
};
int main()
{
const C* const p = new const C;
C* const q = const_cast<C*>(p); // OK, but writes through q cause UB
// ...
delete p; // valid, it doesn't matter that p and *p are const
return 0;
}
Ответ 2
В примере с кучей new
возвращает указатель на неконстантный. Тот факт, что вы сохранили его в указателе на const (а затем const_cast
отредактировал его обратно на указатель на неконстантный), не изменяет того факта, что сам объект не является константой так же, как стек -ограниченный.
Однако вы можете создать объект const в куче:
const Class* object = new const Class();
В таком случае приведение к указателю на не-const и вызов неконстантного метода будет той же самой ситуацией, что и объект, связанный со стеком const.
(Идея создания объекта const в куче была для меня новой, я никогда не видел этого раньше. Спасибо Чарльзу Бейли.)
Ответ 3
Да, объект, выделенный для кучи, может быть const. Рассмотрим этот отрывок из примера в 7.1.5.1/5:
const int* ciq = new const int (3); // initialized as required
int* iq = const_cast<int*>(ciq); // cast required
*iq = 4; // undefined: modifies a const object
Пример, который вы задали в вопросе, прекрасен, потому что вы не просите new
создать объект const; вы просто сохраняете результат в указателе на константу.
Ответ 4
Очевидно:
struct Foo {
const int Bar;
Foo() : Bar(42) { }
};
Foo* foo = new Foo;
const_cast<int&>(foo->Bar); // don't do this.
Ответ 5
Не забывайте изменяемые члены
Это не будет неопределенным поведением, если NonConstMethod только модифицирует mutable
квалифицированных членов (см. 7.1.5.1 (4)) класса с константой. Да, в противном случае это поведение undefined.
const A* p = new(const A);
A *q = const_cast<A*>(p);
q->NonConstMethodThatModifiesMembers(); // undefined behaviour!
q->NonConstMethodThatOnlyModifiesMutableMembers(); // defined behaviour!
Ответ 6
const_cast может вызвать UB, когда объект действительно доступен только для чтения (например, компилятор может создавать такие объекты, когда вы используете жестко закодированные строки в своем коде, помещая их в определенные области памяти, которые только читаются) по какой-либо причине, Это не будет происходить с выделенными кучами объектами, независимо от того, как вы храните их ссылку (указатель const, const reference, что угодно).