Может ли объект, выделенный в куче, быть константным в C ++? - PullRequest
18 голосов
/ 18 декабря 2009

В 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?

также неопределенное поведение?

Ответы [ 6 ]

18 голосов
/ 18 декабря 2009

Да. Законно строить и уничтожать 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;
}
10 голосов
/ 18 декабря 2009

В вашем примере с кучей new возвращает указатель на неконстантный. Тот факт, что вы сохранили его в указателе на const (а затем const_cast вернул его обратно в указатель на неконстантный), не меняет того факта, что сам объект не является константным так же, как стек Выделено одно.

Однако вы можете создать объект const в куче:

const Class* object = new const Class();

В таком случае приведение к указателю на неконстантный и вызов неконстантного метода будет в той же ситуации, что и объект, выделенный из стека констант.

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

2 голосов
/ 18 декабря 2009

Да, объект, выделенный в куче, может быть постоянным.Рассмотрим этот отрывок из примера в 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;вы просто сохраняете результат в виде указателя на константу.

1 голос
/ 18 декабря 2009

Не забудьте изменяемые члены

Это не будет неопределенным поведением, если NonConstMethod изменяет только mutable квалифицированных членов (см. 7.1.5.1 (4)) класса с квалифицированным const. Да, в противном случае это неопределенное поведение.

const A* p = new(const A);
A *q = const_cast<A*>(p);
q->NonConstMethodThatModifiesMembers();             // undefined behaviour!
q->NonConstMethodThatOnlyModifiesMutableMembers();  // defined behaviour!
1 голос
/ 18 декабря 2009

Очевидно:

struct Foo {
  const int Bar;
  Foo() : Bar(42) { }
};

Foo* foo = new Foo;
const_cast<int&>(foo->Bar); // don't do this.
0 голосов
/ 18 декабря 2009

const_cast может вызвать UB, когда объект фактически доступен только для чтения (например, компилятор может создавать такие объекты, когда вы используете жестко закодированные строки в своем коде, помещая их в определенные области памяти, которые только для чтения) по какой-то причине , Это не произойдет с объектами, выделенными из кучи, независимо от того, как вы сохраняете их ссылку (указатель const, указатель const и т. Д.).

...