Вопрос по const-correctness, undefined-behavior, const, c++ – Может ли объект, выделенный в куче, быть константным в C ++?

17

В C ++ объект, выделенный из стека, может быть объявлен:const

const Class object;

после этого попытка вызова неконстантного метода для такого объекта является неопределенным поведением:

const_cast( &object )->NonConstMethod(); //UB

Может ли выделенный кучей объект бытьconst с такими же последствиями? Я имею в виду, возможно ли следующее:

const Class* object = new Class();
const_cast( object )->NonConstMethod(); // can this be UB?

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

Хм, после публикации моего ответа я понял, что он может также применяться к вашему выделенному стеку объекту. Можете ли вы предоставить больше информации о том, почему в качестве примера стека используется UB? Andreas Brinck
Нет, этоs 7.1.5.1/4 - модификация объекта const. sharptooth
@sharptooth Спасибо! Andreas Brinck
Пример стека является наиболее очевидным. Например, вы вызываете некоторую функцию и передаете указатель const на такой объект, и где-то очень глубоко в стеке вызовов выполняется const_cast и вызывается неконстантный метод - приветствуем UB, что очень плохо для переносимости. sharptooth

Ваш Ответ

6   ответов
1

Очевидно:

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

Foo* foo = new Foo;
const_cast<int&>(foo->Bar); // don't do this.
</int&>
Умная интерпретация вопроса, хотя небольшая ошибка в коде, она должна бытьint& нетint* Aidiakapi
0

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

Память только для чтения не является проблемой. Вопрос в том, является ли объект постоянным. Неопределенное поведениебудут произойдет с объектами, выделенными в куче, если они выделены как const, и вы записываете в них неконстантный путь доступа (например, тот, который вы получаете при использовании const_cast). Ваша конкретная реализация может позволить себе определить, что происходит в этой ситуации, но насколькостандарт обеспокоен, это 'все еще не определено. Rob Kennedy
1

Дон»забытьизменчивый члены

Это победилоНеопределенное поведение, если 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!
</a*>
Не могли бы вы объяснить, как вы пришли к такому выводу из той части стандарта, которую вы цитировали? Rob Kennedy
Ok Вы'верно. Я предположил, что r-значение всегда не модифицируется, но это предположение недержись WolfgangP
Я изменил свой ответ, потому что первый был неверным. Я надеюсь, что мой новый ответ добавляет еще один аспект в обсуждение. WolfgangP
Вы, кажется, превратили свой ответ в вопрос. Rob Kennedy
17

Да. Это'законно построить и уничтожить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;
}
</c*>
@ Андреас Бринк. UB только пытается изменить объект, который объявлен как const. Вы можете отказаться от const, если объект был изначально объявлен как неконстантный. sharptooth
Андреас, помимо того, что сказал JK, const_cast 's часто используется для реализации таких вещей, как const operator [] через неконстантный оператор []. Не уверен, если этоИспользование UB, но каждый делает это. Stefan Monov
@ Чарльз, это имело бы значение, еслиp был выделен толькоnew C вместоnew const C? (Я'думаю, да). Andreas Brinck
Хорошо, чувствуя себя немного глупо, но какова цель const_cast, если вызов методов для результирующего указателя всегда может быть UB? Andreas Brinck
10

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

Тем не менее, выМожно создайте объект const в куче:

const Class* object = new const Class();

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

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

Вы можетеМожно удалить через указатель const и указатель на const. CB Bailey
Спасибо за это, яуточнил мой ответ. Greg Hewgill
new возвращает указатель, являющийся значением. Он может быть назначен постоянному или неконстантному указателю. Результатом new может быть указатель на const или указатель на неконстантный объект в зависимости от типа объекта.обновленный», В случае неконстантного объекта указатель может быть назначен указателю на неконстантный или указателю на константные (обычные) правила, но если выновый» const-объект, который вы можете назначить только указателю на const. CB Bailey
2

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

Пример, который вы привели в вопросе, хорош, потому что выне спрашиватьnew сделать константный объект; вы'просто сохранить результат в указателе на константу.

Похожие вопросы