Почему C++ позволяет вызывать деструктор константного объекта вручную?

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

class Composition
{
    public:
    // ...
    const Object object;
};

// ...

Composition composition;
composition.object.~Object();

Ответы (2 шт):

Автор решения: Bogdan

Отсюда:

The purpose of the destructor is to free the resources that the object may have acquired during its lifetime.

Note that calling a destructor directly for an ordinary object, such as a local variable, invokes undefined behavior when the destructor is called again, at the end of scope.


Задача деструктора - освободить ресурсы, которые он может захватить в процессе жизни.

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

Деструктор - специальный метод класса, должен вызываться один раз. Он не меняет состояние объекта. Он его разрушает. Поэтому к нему не применяется семантика const и volatile (как верно заметил AlexGlebe).

В примере дважды произойдет вызов деструктора (напрямую и при выходе из области видимости) и UB в качестве результата.

P.S. Если язык позволяет разыменовать нулевой указатель, то это не значит, что так можно делать.

→ Ссылка
Автор решения: AlexGlebe

Стандарт:

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.6.1) are not applied on an object under destruction. They stop being in effect when the destructor for the most derived object (1.8) starts. A destructor shall not be declared with a ref-qualifier.

Перевод:

Деструктор используется для уничтожения объектов своего типа. Деструктор не принимает параметров, и для него нельзя указать тип возвращаемого значения (даже void). Адрес деструктора не берется. Деструктор не должен быть статичным. Деструктор может быть вызван для объекта типа const, volatile или const volatile. Деструктор не должен быть объявлен как const, volatile или const volatile (9.3.2). семантика const и volatile (7.1.6.1) не применяется к разрушаемому объекту. Они перестают действовать, когда запускается деструктор для самого производного объекта (1.8). Деструктор не должен быть объявлен с ref-квалификатором.

Логика простая, у объекта жизнь когда-нибудь заканчивается. Даже у константного.

// g++ -std=c++11 -Wall constdestr2.cpp
#include <new>
class C{
public :
  C(int x):i{x}{}
  C(C const && c):i{std::move(c.i)}{}
  ~C(){}
private :
  int i ;
};

int main(){
  // память где-то далеко
  char mem [ sizeof ( C ) ] ;
  // ручное создание константного объекта
  C const * c = new ( mem ) C { 7 } ;
  // выделяем новую память
  char mem2 [ sizeof ( C ) * 2 ] ;
  // перенос константного объекта
  C const * c2 = new ( mem2 ) C { std ::  move  ( * c ) } ;
  // ручное удаление константы
  c -> ~ C ( ) ;
  // теперь вектор констант в другом месте
  // ручное удаление константы
  c2 -> ~ C ( ) ;
}

Здесь пример увеличения размера массива константных объектов. Где каждый объект нуждается в переносе : конструктор переноса и вызов деструктора.

→ Ссылка