Видалення покажчика на const (T const *)


89

У мене є основне питання стосовно покажчиків const. Мені не дозволено викликати будь-які функції, що не є учасниками const, за допомогою вказівника const. Однак мені дозволено це робити на покажчику const:

delete p;

Це викличе деструктор класу, який по суті є неконстентним 'методом'. Чому це дозволено? Чи просто для підтримки цього:

delete this;

Або є якась інша причина?

Відповіді:


112

Це для підтримки:

// dynamically create object that cannot be changed
const Foo * f = new Foo;

// use const member functions here

// delete it
delete f;

Але зверніть увагу, що проблема не обмежується динамічно створюваними об'єктами:

{
 const Foo f;
 // use it
} // destructor called here

Якщо деструктори не можна було викликати на об'єктах const, ми не могли б використовувати об'єкти const взагалі.


21
+1 за останню вашу редакцію. Я думаю, що це справжня причина. Автоматичний виклик деструктора для об'єкта const - майже такий самий, як і видалення f; де f - покажчик на const.
bayda

const Foo * fабо Foo const * fне є вказівником const на Foo. Найцікавіше заперечити Фу. Foo * const f є вказівником const на Foo.
user11373693

48

Поставте це так - якби це не було дозволено, не було б можливості видалити об'єкти const без використання const_cast.

Семантично const - це ознака того, що об’єкт повинен бути незмінним. Однак це не означає, що об’єкт не слід видаляти.


3
Деструктори можуть мутувати об'єкти досить жорстоко, тому це має бути якесь дивне вживання слова "незмінний", про яке я раніше не знав ...
ДартГізка,

1
@DarthGizka ні, деструктори переносять вас із стану, де є об’єкт, до стану, де його немає. С ++ не визначає жодного методу для спостереження за "мутацією" після знищення
Калет,

@ Калет: стандарт може не дозволяти вам дивитись на об'єкт після того, як його деструктор завершився, але вам, безумовно, дозволено розглядати побічні ефекти, викликані руйнуванням. Отже, обставини можна легко організувати, щоб зробити мутацію «незмінного» об'єкта спостережуваною. У США вбивство важко притягнути до кримінальної відповідальності, коли немає тіла, але це все-таки вбивство (і можуть бути інші докази, достатні для винесення обвинувального вироку). Та сама різниця.
DarthGizka,

6

Мені не дозволено викликати будь-які функції, що не є учасниками const, за допомогою вказівника const.

Так.

class Foo
{
public:
  void aNonConstMemberFunction();
};

Foo* const aConstPointer = new Foo;
aConstPointer->aNonConstMemberFunction(); // legal

const Foo* aPointerToConst = new Foo;
aPointerToConst->aNonConstMemberFunction(); // illegal

Ви переплутали вказівник const на об'єкт, який не є const, з вказівником, що не є const, на об'єкт const.

Сказавши, що,

delete aConstPointer; // legal
delete aPointerToConst; // legal

законно видалити будь-яку з причин, зазначених в інших відповідях тут.


5

Конструктори та деструктори не слід розглядати як "методи". Вони є спеціальними конструкціями для ініціалізації та руйнування об’єкта класу.

"покажчик const" означає, що стан об'єкта не буде змінено, коли над ним виконуються операції, поки він живий.


5

Інший спосіб подивитися на це: точне значення покажчика const полягає в тому, що ви не зможете вносити зміни до об’єкта, на який спрямовано, який буде видно через той чи інший вказівник або посилання на той самий об’єкт. Але коли об’єкт руйнується, всі інші вказівники на адресу, раніше зайняту видаленим об’єктом , більше не є вказівниками на цей об’єкт . Вони зберігають одну і ту ж адресу, але ця адреса вже не є адресою будь-якого об'єкта (насправді вона може незабаром бути повторно використана як адреса іншого об'єкта).

Це розрізнення було б більш очевидним, якби вказівники в C ++ поводились як слабкі посилання, тобто як тільки об'єкт буде знищений, для всіх наявних покажчиків на нього відразу буде встановлено значення 0. (Це те, що вважається занадто дорогим під час виконання, щоб накласти на всі програми C ++, і насправді неможливо зробити його цілком надійним.)

ОНОВЛЕННЯ : Читаючи це назад через дев'ять років, це по-адвокатськи. Зараз я вважаю вашу оригінальну реакцію зрозумілою. Заборонити мутацію, але дозволити знищення, очевидно, проблематично. Мається на увазі договір const покажчиків / посилань на те, що їх існування буде діяти як блок знищення цільового об'єкта, він же автоматичний збір сміття.

Звичайним рішенням цього є використання замість нього майже будь-якої іншої мови.


Якщо ви не можете знищити речі, на які вказують покажчики, щоб погодитися, як ви маєте справу з std::unique_ptr<const T>закінченням життя?
Калет,

@Caleth, тоді в C ++ цього рішення не буде. Це лише один із прикладів загальної проблеми: у C ++ модифікатор const означає "Ви не можете мутувати ціль, за винятком одного сенсу, коли ви можете повністю її зруйнувати і зробити всі інші посилання на неї недійсними та джерелами невизначеної поведінки". Ось чому, на мою думку, подібне запитання повинно діяти як підказка для розгляду інших мов. У ньому є отвори для UB, які неможливо вирішити без використання іншого базового підходу.
Даніель Ервікер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.