среда, октября 14, 2009

Вызов деструктора константного объекта

Интересная штука получается с константными объектами. Не константные функции у них вызывать нельзя. То есть получается, что и деструктор звать нельзя. Потому что деструктор const объявлять нельзя. Конструктор, кстати, тоже нельзя. ( Я знаю, что на слово вы мне не поверите, поэтому привела куски из Стандарта в конце поста ).

В связи с чем возникают вопросы. А что будет вот с таким кодом? Будет ли вызван деструктор при выходе из блока?

{
const CMyClass p;
}


А вот это как же? Скомпилируется?

{
const int* p = new int(10);
delete p;
}


На самом деле всё здесь нормально и всё компилируется и работает. Потому что для деструктора сделано исключение и его можно звать для константных объектов.

Об этом лучше помнить, чтобы потом не писать вот так:
delete const_cast<ReferenceCounter*>(this);


Куски из Стандарта по теме:
[class.dtor] 12.4/2:

A destructor is used to destroy objects of its class type. A
destructor takes no parameters, and no return type can be specified
for it (not even void). The address of a destructor shall not be
taken. A destructor shall not be static. A destructor can be invoked
for a const, volatile or const volatile object. A destructor shall
not be declared const, volatile or const volatile (9.3.2). const and
volatile semantics (7.1.5.1) are not applied on an object under
destruction. Such semantics stop being into effect once the destructor for the most derived object (1.8) starts.


[expr.delete] 5.3.5/2:

[Note: a pointer to a const type can be the operand of a
delete-expression; it is not necessary to cast away the
constness (5.2.11) of the pointer expression before it
is used as the operand of the delete-expression. ]


Ссылки по теме:
comp.lang.c++.moderated - Delete a const pointer?
comp.lang.c++.moderated - Why can operator delete be called on a const pointer?

13 комментариев:

  1. Интересный факт насчет деструктора. Вобщем-то я и раньше так писал, но не думал, что есть отдельный пункт в стандарте. Спасибо!

    >> Конструктор, кстати, тоже нельзя.
    Конструктор, строго говоря, вообще не метод класса - скорее, статический метод, ведь он вызывается когда объект еще не существует.

    ОтветитьУдалить
  2. Ну тут конечно все достаточно очевидно. Было бы странно, если бы было как-нибудь по-другому.
    Например, что бы значил спецификатор const у конструктора или деструктора? Наверняка не то же самое, что и у обычной функции.

    Но тем не менее, спасибо. Иногда бывает полезно задуматься и над очевидными вещами :)

    ОтветитьУдалить
  3. Еще бы сто лет писал delete p для константного объекта и не задумывался бы, если б не прочитал :( Наверное, пора начинать покуривать стандарт перед сном.

    ОтветитьУдалить
  4. Спасибо большое! Интерсная штука)

    ОтветитьУдалить
  5. кстати интересна в этой связи парадигма уничтожающей функции,
    например Release(), в этом случае константность указателя на объект будет также означать невозможность удаления такого объекта.

    ОтветитьУдалить
  6. Ну, собственно, именно для таких случаев и придумали const_cast… Хотя ситуация, когда объект должен удаляться кем-то, кто имеет к нему доступ только по константному указателю, это огрехи в проектировании.

    ОтветитьУдалить
  7. имел в виду, что это можно использовать в каких-нибудь полезных целях :)

    ОтветитьУдалить
  8. Анонимный21/10/09 18:49


    >> Хотя ситуация, когда объект должен удаляться кем-то, кто имеет к нему доступ только по константному указателю, это огрехи в проектировании.

    Это не огрехи проектирования, а умные указатели...

    ОтветитьУдалить
  9. Анонимный26/10/09 01:35

    Cпасибо - интересный пост! Интересные факты, порадовали!

    ОтветитьУдалить
  10. Анонимный29/10/09 18:25

    Опечатка в первом абзаце.
    Декструктор вместо деструктор

    ОтветитьУдалить
  11. Анонимный13/11/09 12:33

    вероятно лучше как-то так
    delete[] p;

    ОтветитьУдалить
  12. delete[] p;
    стоило бы писать если б создавался масив интов:
    const int* p = new int[10];
    в примере создается только один инт и инициализируется значением 10;
    const int* p = new int(10);
    так что все правильно.

    ОтветитьУдалить