2013-02-16 3 views
1

Мне было интересно, действительно ли деструкторы класса по умолчанию делают что-либо при их вызове.Do Destructors Do Anything?

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

Означает ли это, что деструктор класса можно рассматривать как унаследованную виртуальную функцию, которую могут иметь все классы и ее переопределение (удалить указатели и т. Д. И очистить переменные-члены), но если это не переопределено, он ничего не сделает?

Если это так, то деструктор не может быть использован как функция «очистить все данные» и сделать некоторые части кода более эффективными, очистив динамически распределенную память и повторно используя ее, а не получая компьютер найти новый блок памяти в куче?

Спасибо.

+0

Если вызов деструктора для ручного освобождения памяти, что произойдет, если объект будет уничтожен? Я не уверен, на что вы нацелены, но, вероятно, лучше подходит для простой функции-члена. – Bingo

+0

Ответ на этот вопрос может помочь: http: //stackoverflow.com/questions/1036019/does-calling-a-destructor-explicitly-destroy-an-object-completely –

+0

Рассмотрите возможность использования пулов памяти или размещения new/delete, а не такой вид оптимизации. И помните: «преждевременная оптимизация - это корень всего зла». – doc

ответ

2
  • Конструктор по умолчанию вызывает конструктор по умолчанию всех переменных-членов, не включая примитивные типы (char, int, указатели).
  • Деструктор может быть вызван явно, но это не означает, что объект-декодер. Если объект находится в стеке, то он ничего не может с этим поделать.
  • Деструкторы по умолчанию не являются виртуальными, но они действительно должны быть, если вы планируете наследовать от класса.
  • Если объект освобожден (выходит за пределы области видимости, удаляется из кучи или закрывается объект каким-либо образом), будет вызываться дескриптор.
+0

То, что я имел в виду под «виртуальным», заключалось в том, что каждый класс получает по умолчанию (и может называть его), но он просто ничего не делает; Я не имел в виду в смысле наследования :). Но означает ли это, что любые переменные-члены класса, являющиеся структурой или классом, также будут иметь свои деструкторы? – Edward

+0

@Edward Да. Неявно, всегда. Если вы пишете деструктор для своего класса, вам все равно не нужно называть дескрипторов ваших членов. Вам просто нужно позаботиться о «удалении» динамически распределенных объектов, закрытии открытых файлов и выпуске других ресурсов, связанных с вашим объектом. Если у вас нет таких вещей, вам не нужно писать деструктор. – Notinlist

+1

Пункт о наследовании вводит в заблуждение: вполне безопасно иметь базовый класс с не виртуальным деструктором. Единственный раз, когда деструктор должен быть виртуальным, - это когда вы собираетесь использовать статический тип базового класса во время полиморфизма времени выполнения (другими словами, когда вы собираетесь обращаться к экземпляру с динамическим типом «производный класс» с помощью указателя/(не-const) ссылку типа «базовый класс»). –

1

В дополнение к ответу Notinlist в:

По умолчанию конструкторы называют конструкторами своих базовых классов.

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

Вы как-то описываете пул памяти. Если вы хотите, ваши объекты могут приобретать и возвращать буферы памяти в/из какой-либо системы пула, которую вы придумываете. Но по большей части ассигнования достаточно быстры и довольно редки, что для людей это обычно не так. Не сказать, что они нечасты, но они должны происходить много, чтобы обратить внимание на этот удар производительности.

2

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

Рассмотрим этот код:

#include <iostream> 

struct A 
{ 
    ~A() 
    { 
     std::cout << "A::~A" << std::endl; 
    } 
}; 

struct B 
{ 
    A a; 
}; 

int main() 
{ 
    B b; 
    std::cout << "Calling b.~B()" << std::endl; 
    b.~B(); 
    std::cout << "Done" << std::endl; 
} 

You'll see, что вызов B По умолчанию деструктор вызывает A 's деструктора, потому что B содержит A:

Calling b.~B() 
A::~A 
Done 
A::~A 

Только когда b выходит из область развертки развернута, и синтезированный B::~B(), и, в свою очередь, A::~A(), прежде чем их память свободна.

+0

Вы выводите не свой код (f() vs ~ B()). – Kleist

+0

Спасибо @Kleist, я упростил свой код в какой-то момент, но забыл обновить вывод. http://ideone.com/8fxvWQ показывает, что он работает, как указано. – Johnsyweb

1

Вызов деструктора вручную - это, как правило, плохая идея. В разделе часто задаваемых вопросов о C++ около destructors есть много хорошей информации об этом.

Если вы хотите уничтожить объект явно, вы можете использовать дополнительные области действия, чтобы вызвать безопасный вызов деструктора (см. Этот FAQ entry). Этот метод также предотвращает использование экземпляра объекта, который был уничтожен. Хотя экземпляр может показаться полезным, на самом деле это не так.

Если ваше намерение освободить некоторые, но не все из ресурсов, принадлежащих экземпляру класса вы можете попробовать две вещи:

  • Определите метод clear() (или аналогичный) на классе.
  • Убедитесь, что инвариант класса поддерживается после вызова clear().

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

Хорошо понятый и часто практикуемый метод управления ресурсами в C++ - это сбор ресурсов - это инициализация (часто сокращенно RAII, но игнорирование имени, если оно запутывает, концепция понятна). См. Статью this в Википедии или об этом answer за полезную информацию.

Вот Т.Л., д-р, хотя:

  • Время жизни ресурса всегда должны быть привязаны к жизни объекта.
  • Срок службы объекта начинается, когда конструктор завершается
  • Срок службы объекта заканчивается, когда деструктор завершается.

После этого идиома обычно предотвращает проблемы управления ресурсами C++ до их возникновения.

+0

Я до сих пор не уверен, почему экспликация, называющая деструктора, является плохой идеей. Если деструктор имеет в себе защитные элементы перед удалением переменных, таких как указатели (например, если (pointer! = Nullptr) delete pointer;), то, безусловно, это не должно быть вредным. Это на всякий случай, когда программист забывает, что есть и не уничтожается по умолчанию деструктором (например, переменные-члены или унаследованные классы, которые будут вызваны их деструкторами)? – Edward

+0

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