Деструктор не вызывается после уничтожения объекта.

Я понятия не имел, почему это не работает. Следующий Function создается путем размещения new. Предоставляется функция, которая проверяет, следует ли ее уничтожить, и, если да, вызывает ее деструктор вручную.

Вот тестовый пример, где кажется, что деструктор никогда не вызывается:

/* Represents a function at runtime */ 
class Function {
public:
  /* Creates an invalid function */
  Function():codeptr(0) { }

  /* Creates a function with the given code pointer */
  Function(void *codeptr):codeptr(codeptr) { }

  /* Frees the function machine code */
  ~Function() {
    if(*this) {
      /* <- I explicitly put a debug output here! */
      destroyLLVMCode(codeptr);
    }
  }

public:
  /* Returns true if the function is valid 
   * (if the code pointer is non-null)
   */
  operator bool() const { return codeptr != 0; }

  /* Destroy this function by calling its destructor */
  void destroy() { ~Function(); }

private:
  void *codeptr;
};

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

#include <new>
#include <cstdlib>

int main() { 
  void *buffer = std::malloc(sizeof(Function));
  Function *f = new (buffer) Function(someExecutableLLVMCode);
  /* more code .. register with symbol tables etc.. */
  f->destroy();
}

Вы можете видеть, что я вызываю деструктор в строке, читающей ~Function(). Компилятор принимает, но не вызывает его: я проверил его, проверив, действительно ли он удаляет предоставленный мной код LLVM (поместите некоторый код в деструктор перед удалением кода LLVM, на который указывает codeptr, в случае, если Function действительно).

Позже я узнал, что вызывает это. Не могли бы вы дать мне объяснение?


person Johannes Schaub - litb    schedule 13.12.2010    source источник
comment
Этот код никоим образом не создает функцию и никогда не вызывает никаких методов функции, поэтому неудивительно, что он также никогда не уничтожает какие-либо объекты функции ...   -  person Chris Dodd    schedule 13.12.2010
comment
@Johannes, как вы здесь создаете экземпляр? Где это место размещения new?   -  person Nikolai Fetissov    schedule 13.12.2010
comment
@ Йоханнес: сделай перерыв, вздремни, да что угодно. ;-) ваш пример кода не иллюстрирует проблему. вы говорите, что нашли причину, но просите объяснений. это просто путаница. можешь удалить вопрос и опубликовать завтра?   -  person Cheers and hth. - Alf    schedule 13.12.2010
comment
Пожалуйста, добавьте полный код, чтобы мы могли посмотреть   -  person Arunmu    schedule 13.12.2010
comment
Я просто добавляю его и вызываю функцию уничтожения где-нибудь во внешнем коде. Я не считал это важным. Я включу это в вопрос. Подожди.   -  person Johannes Schaub - litb    schedule 13.12.2010
comment
Как была использована функция new, не ясно. и как вы убедились, что Деструктор не вызывается?   -  person Arunmu    schedule 13.12.2010
comment
Я не могу опубликовать весь код, потому что он с закрытым исходным кодом. Итак, я публикую тестовый пример. Но этот тестовый пример тоже демонстрирует эту проблему. Должен признать, это непростой вопрос.   -  person Johannes Schaub - litb    schedule 13.12.2010
comment
Ночью Йоханнес - полезный и продуктивный член сообщества Stack Overflow. Днем он пишет код с bool функциями преобразования.   -  person James McNellis    schedule 13.12.2010
comment
@Johannes: Safe Bool Idiom на artima.com/cppsource/safebool.html - ›Думаю, вам будет интересно читать :)   -  person Matthieu M.    schedule 13.12.2010


Ответы (3)


Это потому, что ~Function(); здесь синтаксически не является вызовом деструктора. Вместо этого используйте this->~Function();.

~Function(); анализируется как оператор ~ и создание объекта Function в стеке. Function класс имеет operator bool, поэтому он будет скомпилирован.

person Kirill V. Lyadvinsky    schedule 13.12.2010
comment
Но если это не так, если вам нужно написать, скажем, Function::~Function(), тогда что ~Function() анализируется как? Применять побитовое отрицание к временному Function объекту? Я думаю, это не должно компилироваться. ОБНОВЛЕНИЕ ОН: у него неявное преобразование в bool. J O H A N N E S, не делай этого! - person Cheers and hth. - Alf; 13.12.2010
comment
Function::~Function() тоже не сработает. Стандарт говорит, что вы должны написать ptr->~Function(). - person Kirill V. Lyadvinsky; 13.12.2010
comment
Что ж, Function :: ~ Function () будет работать нормально. Но насчет ~Function() вы правы. Это описано в 5.3.1 / 9 священного Стандарта C ++. - person Johannes Schaub - litb; 13.12.2010
comment
@Kirill: Я думаю, что Function::~Function() в порядке, это qual-id, а в стандарте сказано [Примечание: явный вызов деструктора всегда должен быть написан с использованием оператора доступа к члену (5.2.5) или квалифицированный идентификатор (5.1); в частности, унарное выражение ˜X() в функции-члене не является явным вызовом деструктора (5.3.1). - конечное примечание] (раздел 12.4 [class.dtor] проекта n3225) - person Ben Voigt; 13.12.2010
comment
Проклятие. Я должен был поместить оператор печати управления за пределами if(*this). Тогда люди проверили бы его и сказали бы, Чувак, деструктор is вызван !. Но на самом деле это был бы деструктор временного ха-ха. - person Johannes Schaub - litb; 13.12.2010
comment
Стандарт C ++ 12.4 гласит: [Примечание: явный вызов деструктора всегда должен быть написан с использованием оператора доступа к члену (5.2.5); в частности, унарное выражение ̃X () в функции-члене не является явным вызовом деструктора (5.3.1). ] - person Kirill V. Lyadvinsky; 13.12.2010
comment
@Kirill V. Lyadvinsky: +1 за красивое объяснение, почему он компилируется и как вызвать деструктор. - person Nawaz; 13.12.2010
comment
@Ben Voigt или часть с квалифицированным идентификатором не входит в текущий Стандарт. - person Kirill V. Lyadvinsky; 13.12.2010
comment
Святая корова. Прекрасный день! Я только что узнал кое-что новое о C ++! - person wilhelmtell; 13.12.2010
comment
@Kirill: Похоже на стандартную ошибку. Принято квалифицированный идентификатор, и сноска должна была быть изменена, чтобы отразить это (в текущих версиях C ++ 0x это так), но сноска всегда была информационной и необязательной. Раздел 3.4.3 [basic.lookup.qual] управляет поиском деструкторов как квалифицированных идентификаторов. - person Ben Voigt; 13.12.2010
comment
@ Кирилл, это не имеет значения. Это примечание, поэтому оно никак не влияет на валидность программ C ++. Class::~Class() - это вызов деструктора, потому что Class::~Class относится к деструктору (5.1 / 7). - person Johannes Schaub - litb; 13.12.2010
comment
Я думаю, вы могли бы написать (~Function)(), и он вызвал бы деструктор вместо побитового отрицания :) - person Johannes Schaub - litb; 13.12.2010
comment
А также раздел 5.2.4 [expr.pseudo] может вступить в игру. - person Ben Voigt; 13.12.2010
comment
@Johannes: круглые скобки определенно разрешены в объявлении (раздел 12.4 p1), не уверен в месте вызова. Я думаю, что грамматика по-прежнему будет рассматривать это как применение оператора поразрядного дополнения ~. - person Ben Voigt; 13.12.2010
comment
@Johannes, хорошо, я только что тестировал на GNU C ++ 4.4.4. По-прежнему требуется оператор доступа к члену, Function::~Function() без this-> не компилируется. - person Kirill V. Lyadvinsky; 13.12.2010
comment
@Ben имя типа не является выражением, поэтому я не думаю, что это будет :) - person Johannes Schaub - litb; 13.12.2010
comment
@ Йоханнес: Конечно. Попробуйте эту разбивку: унарное-выражение: унарный-оператор выражение-приведение, унарный-оператор: ~ и < i> cast-expression: унарное-выражение, унарное-выражение: postfix-expression, postfix-expression < / i>: первичное-выражение, первичное-выражение: id-выражение, id-выражение: unqualified-id, unqualified-id: идентификатор ... и имя типа является идентификатором. - person Ben Voigt; 13.12.2010
comment
@Ben, кажется, я неправильно понял этот вопрос, поскольку все компиляторы согласны с вами. Однако этот вопрос кажется неоднозначным: string();. Если имя типа будет первичным выражением, то здесь возникает двусмысленность между вызовом функции и функциональным приведением. Я не думаю, что текст разрешает эту двусмысленность. - person Johannes Schaub - litb; 13.12.2010
comment
Поэтому у меня (или было, если у вас есть удовлетворительное объяснение предстоящих проблем) сложилось впечатление, что все наоборот: идентификатор может быть именем типа, но имя типа не является выражением идентификатора. Я получил это из 5.1.1 / 6, в котором говорится, что идентификатор - это id-выражение, при условии, что он был соответствующим образом объявлен ... (подчеркните мой). - person Johannes Schaub - litb; 13.12.2010
comment
У вас будут не только проблемы с этим, но и с sizeof. Будет ли sizeof (string) версией, которая измеряет размер (type-id) или размер унарного выражения? А что насчет string * s; - это умножение или объявление? Дело в том, что зная только, что string является типом, достаточно знать, как его разбирать. Например, в этом весь смысл typename в шаблонах. - person Johannes Schaub - litb; 14.12.2010
comment
@ Между тем, я разговаривал с комитетом, и они сказали, что он также намерен отклонить (~T)(). Надеюсь, этот вопрос прояснится. - person Johannes Schaub - litb; 18.12.2010

Измените явный вызов деструктора на

this->~Function();

В настоящее время функция ~ конструирует "функцию", а затем вызывает побитовый оператор ~ (законный, потому что у вас есть преобразование в bool), а затем уничтожает его, а не вызываемый объект.

person Keith    schedule 13.12.2010

Насколько я помню, деструктор нельзя вызвать явно. Попробуйте переместить код очистки из деструктора в другую функцию и вместо этого вызовите его.

person ruslik    schedule 13.12.2010
comment
Вы можете вызывать деструкторы явно (гораздо сложнее обсуждать явные вызовы конструкторов, поскольку синтаксиса для вызовов конструкторов нет вообще, он находится на семантическом уровне, но вызовы деструкторов даже не имеют этой терминологической проблемы: все очень ясно). - person Cheers and hth. - Alf; 13.12.2010
comment
мы можем вызвать деструктор только как показано ниже :: Obj o; o. ~ Obj (); Не то что в методе mayBeDestroy. Это должно было дать ошибку компиляции. В противном случае он должен называться Function :: ~ Function (); - person Arunmu; 13.12.2010