Когда я должен использовать свою собственную функцию уничтожения в C ++?

0

Недавно я изучаю ООП с использованием C++, и я совершенно смущен, когда должен использовать собственную функцию уничтожения в следующем случае:

class T1{
private:
    int data;

public:
    T1(){...};
    ~T1(){}; // should I write my own function here?
};

class T2{
private:
    T1* pointer_to_T1;

public:
    T2(){...};
    ~T2(){}; // should I write my own function here?
};

class Node{
public:
    int data;
    Node* next;
};

class T3{
private:
    int size;
    Node* head;
public:
    T3(size){
        head = new Node[size];
    }
    ~T3(){}; // should I write my own function here?
};

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

  • 0
    Не забудьте сделать ваши деструкторы виртуальными. Это очень важно помнить!
Теги:

7 ответов

0
Лучший ответ

Я попытаюсь ответить в общем виде, не относящемся к вашим фрагментам кода.

Обычно присутствуют два общих сценария, в которых вам понадобится нетривиальный деструктор. Это не полный список; просто самые распространенные сценарии.

1) В (полиморфной) иерархии. Если ваш класс является базовым классом, который должен быть получен, есть очень хороший шанс, что ваш базовый класс должен иметь нетривиальный деструктор. Более того, этот деструктор, вероятно, должен быть virtual. Это позволяет удалить объекты производного класса с помощью указателя базового класса, например:

class Foo
{
public:
  virtual ~Foo(){}
};

class Bar : public Foo
{
};

int main()
{
  Foo* obj = new Bar;
  delete obj;
}

Без virtual деструктора в этой программе будет отображаться Undefined Behavior.

2) Когда ваш класс имеет членов, требуется более чем тривиальное уничтожение. Простой пример: если у вашего класса есть член, который является необработанным указателем (как не в интеллектуальном указателе), который был создан с использованием new. Этот указатель должен быть delete d, и деструктор, вероятно, является подходящим местом для этого. Хорошим признаком того, что ваш класс управляет не-тривиально разрушаемыми членами, является то, что ваш класс имеет либо конструктор копирования, либо оператор присваивания копии (operator=). Если у вашего класса есть либо, то, вероятно, они нуждаются в обоих из них плюс деструктор, чтобы обрабатывать все, что было назначено. (См. Правило из трех). Однако это не единственный признак - у вас может быть только конструктор по умолчанию и по-прежнему нужен деструктор. Это зависит от того, что делает ваш класс.

1

В случае class T3 вы выделяете новую память, поэтому вам придется удалить выделенный сегмент памяти в деструкции.

class T3{
private:
    int size;
    Node* head;
public:
    T3(size){
        head = new Node[size];
    }
    ~T3(){
         delete[] head;
      }; 
};
  • 0
    Теперь у вас неверная семантика копирования. Вам также следует реализовать или удалить конструктор копирования и оператор копирования-назначения в соответствии с правилом трех или, что лучше, использовать std::vector для автоматического управления массивом.
0

Класс T1 не требует явно указывать деструктор. Этого достаточно, чтобы деструктор неявно определялся компилятором.

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

Узел класса не должен явно определять деструктор. Это класс T3, который должен удалить все указатели класса Node, поскольку он контролирует распределение и освобождение узлов.

  • 0
    Откуда вы знаете, что T2 владеет памятью, на которую указывает адрес указателя члена?
  • 0
    @Luchian Grigore Это просто плохой дизайн - использовать необработанный указатель, который не принадлежит классу.
Показать ещё 2 комментария
0

Деструктор класса должен выполнять все действия, необходимые при удалении объекта.

Например, необходимо освободить всю память, динамически распределяемую классом.

0

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

Если объект владеет и управляет ресурсами, вам, вероятно, нужен конструктор. Не забывайте о операторах копирования и присваивания.

  • 0
    И этот деструктор должен быть virtual
0

Вам нужно объявить деструктор:

  • если класс управляет ресурсами, которые должны быть освобождены вручную при их уничтожении;
  • если он должен быть полиморфным базовым классом, и в этом случае ему нужен виртуальный деструктор, чтобы разрешить полиморфное удаление.

В первом случае вам также необходимо предоставить или удалить конструктор копирования и оператор присваивания копии; в противном случае у вас может быть два или более объекта, пытающихся управлять одним и тем же ресурсом. Это называется "Правило трех". Обычно для управления памятью вы можете использовать готовые классы, такие как контейнеры и интеллектуальные указатели; поэтому обычно не нужно гадать с деструкторами самостоятельно. Некоторые люди называют это "Правило нуля".

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

Для ваших конкретных примеров:

  • T1 не нуждается в деструкторе
  • T2 может, в зависимости от того, должен ли он управлять тем, на что указывает указатель. Если это так, рассмотрите замену указателя на умный указатель, такой как std::unique_ptr<T1>.
  • T3 вероятно, делает это, поскольку он управляет динамическим массивом. Вам также нужно будет рассмотреть правило трех; или рассмотрите возможность использования std::vector<Node> для автоматического управления массивом.
0

Объект должен очищать после себя.

IE, если вы когда-либо выделяете память в своем объекте, возможно, выполняетесь в конструкторе, тогда вы должны освободить эту память от деструктора.

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню