В C++ может быть объявлен выделенный стеку объект const
:
const Class object;
после того, как та попытка назвать метод неконстанты на таком объекте является неопределенным поведением:
const_cast<Class*>( &object )->NonConstMethod(); //UB
Может выделенный "куче" объект быть const
с теми же последствиями? Я имею в виду, это возможный что следующее:
const Class* object = new Class();
const_cast<Class*>( object )->NonConstMethod(); // can this be UB?
также неопределенное поведение?
Да. Создание и уничтожение объекта кучи const
является законным. Как и в случае с другими объектами const
, результаты манипулирования им как объектом, отличным от const
(например, посредством const_cast
указателя или ссылки), вызывают неопределенное поведение.
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;
}
В вашем примере кучи new
возвращает указатель на неконстантный. Тот факт, что вы сохранили его в указателе на const (а затем const_cast
вернули его к указателю на неконстантный), не меняет того факта, что сам объект не является константой в том же
Однако вы можете создать константный объект в куче:
const Class* object = new const Class();
В таком случае приведение к указателю на неконстантный и вызов неконстантного -const будет той же ситуацией, что и объект, выделенный в стеке const.
(Идея создания объекта 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; вы просто сохраняете результат в виде указателя на константу.
Не забывайте изменяемые члены
Неопределенное поведение не будет, если NonConstMethod изменяет только изменяемые
квалифицированные члены (см. 7.1. 5.1 (4)) квалифицированного класса const. Да, в противном случае это поведение undefined.
const A* p = new(const A);
A *q = const_cast<A*>(p);
q->NonConstMethodThatModifiesMembers(); // undefined behaviour!
q->NonConstMethodThatOnlyModifiesMutableMembers(); // defined behaviour!
const_cast может вызвать UB, когда объект фактически доступен только для чтения (например, компилятор может создавать такие объекты, когда вы используете жестко закодированные строки в своем коде, помещая их в определенные области памяти, которые доступны только для чтения) по какой-то причине. Этого не произойдет с объектами, размещенными в куче, независимо от того, как вы храните их ссылку (константный указатель, константная ссылка, что угодно).
Очевидно:
struct Foo {
const int Bar;
Foo() : Bar(42) { }
};
Foo* foo = new Foo;
const_cast<int&>(foo->Bar); // don't do this.