2009-12-18 6 views
16

В C++ стек-размещенного объект может быть объявлен const:Может ли выделенный кучей объект быть const в C++?

const Class object; 

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

const_cast<Class*>(&object)->NonConstMethod(); //UB 

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

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

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

+0

Хм, после отправки ответа я понял, что он может также применяться к вашему выделенному стекю объекту. Можете ли вы предоставить дополнительную информацию о том, почему пример стека - UB? –

+0

Пример стека является самым очевидным. Например, вы вызываете некоторую функцию и передаете указатель const на такой объект и где-то очень глубоко в стеке вызовов выполняется const_cast и вызывается неконстантный метод - приветствуем UB, очень плохо для переносимости. – sharptooth

+0

@sharptooth Является ли этот пункт 3.10/15 в действии? –

ответ

16

Да. Законно строить и уничтожать объект кучи 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; 
} 
+1

Хорошо, чувствую себя немного глупо здесь, но в чем цель const_cast, если вызовы методов на результирующем указателе всегда могут быть UB? –

+0

Поскольку неопределенное поведение может быть определено на вашей целевой платформе. const_cast жертвует переносимостью, что часто является компромиссом OK. –

+0

@ Понтус Я до сих пор не понимаю; Использование константы 'const_cast' всегда вызывает UB? (в соответствии со стандартом, мне все равно, будет ли результат на определенной платформе определен). –

10

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

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

const Class* object = new const Class(); 

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

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

+5

Вы можете _can_ удалить через указатель const и указатель на const. –

+1

'new' возвращает указатель, который является rvalue. Он может быть назначен указателю const или не const. Результатом нового может быть указатель на const или указатель на неконстантный объект в зависимости от типа объекта «newed». В случае неконстантного объекта указатель может быть назначен указателю на неконстантный или указатель на константные (обычные) правила, но если вы 'новый' объект const, вы можете назначить только указатель на Уст. –

+0

Спасибо за это, я уточнил свой ответ. –

1

Очевидно:

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

Foo* foo = new Foo; 
const_cast<int&>(foo->Bar); // don't do this. 
+0

Умная интерпретация вопроса, хотя и небольшая ошибка в коде, должна быть 'int &' not 'int *'. – Aidiakapi

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 

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

0

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

+0

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

1

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

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

const A* p = new(const A); 
A *q = const_cast<A*>(p); 
q->NonConstMethodThatModifiesMembers();    // undefined behaviour! 
q->NonConstMethodThatOnlyModifiesMutableMembers(); // defined behaviour! 
+0

Не могли бы вы объяснить, как вы достигаете этого вывода из той части стандарта, которую вы цитировали? –

+0

Хорошо, вы правы. Я предположил, что r-значение всегда не модифицируется, но это предположение не выполняется. – WolfgangA

+0

Вы, кажется, обратили свой ответ в вопрос. –

 Смежные вопросы

  • Нет связанных вопросов^_^