0

Деструкторы в C++ с использованием векторов и указателей

14

У меня есть некоторые вопросы касательно управления памятью в C++. Я знаю, что в деструкторах нужно освобождать память для всего, что было создано с помощью new, а также закрывать открытые потоки файлов и другие потоки. Однако у меня есть сомнения относительно других объектов в C++:

  1. Автоматическое разрушение: Автоматически ли уничтожаются объекты std::vector и std::string?

  2. Векторы указателей: Рассмотрим следующий код:

    std::vector<myClass*>
    

    Если у меня есть вектор указателей на объекты класса myClass, что произойдет, когда будет вызван деструктор вектора? Будет ли автоматически вызван деструктор myClass для каждого объекта, или только уничтожится сам вектор, а объекты, на которые он указывает, останутся в памяти?

  3. Указатели внутри классов: Что произойдет, если у меня есть указатель на другой класс внутри одного класса, например:

    class A {
      ClassB* B;
    }
    

    Если класс A будет уничтожен в какой-то момент в коде, будет ли также уничтожен класс B, или уничтожится только указатель, а класс B останется где-то в памяти?

Спасибо за помощь!

5 ответ(ов)

0

Да, они уничтожаются автоматически (при условии, что членские переменные не являются указателями на std::vector и std::string).

Если у вас есть что-то вроде std::vector, что происходит, когда вызывается деструктор вектора? Вызывается ли автоматически деструктор вашего класса? Или уничтожается только вектор, а все объекты, которые он содержит, остаются в памяти?

Если это vector<MyClass>, то все объекты, содержащиеся в векторе, будут уничтожены. Если это vector<MyClass*>, то все объекты должны быть явным образом удалены с помощью delete (при условии, что класс, в котором находится вектор, владеет этими объектами). Третья альтернатива — это использовать вектор умных указателей, например, vector<shared_ptr<MyClass>, в этом случае элементы вектора не нужно будет явно удалять.

Что произойдет, если внутри класса есть указатель на другой класс?

Указатель B должен быть явно удален с помощью delete. Опять же, можно использовать умный указатель для управления уничтожением B.

0

Когда вы работаете с динамически выделенной памятью в C++ (например, когда вы используете оператор new), вам нужно заботиться о её освобождении, чтобы избежать утечек памяти.

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

Пример:

class Myclass {
private:
    char* ptr; // Указатель на динамически выделенный массив
public:
    // Деструктор, освобождающий память
    ~Myclass() {
        delete[] ptr; // Освобождаем память
    }
};

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

0

Если объекты находятся в автоматическом хранилище, то да. Вы можете создать указатель на std::string, используя std::string* s = new std::string, в этом случае вы должны самостоятельно освобождать память с помощью delete.

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

Если вы выделили b с помощью new, то вам следует явно уничтожить его в деструкторе.

Хорошее правило: используйте delete/delete[] для каждого new/new[], который есть в вашем коде.

Лучшее правило: используйте RAII и предпочитайте умные указатели вместо "сырых" указателей.

0

Это зависит от контекста. std::vector, std::string и MyClass имеют одно общее свойство: если вы объявляете переменную любого из этих типов, она будет выделена в стеке, будет локальной для текущего блока, в котором вы находитесь, и будет разрушена, когда блок завершится.

Например:

{
    std::vector<std::string> a;
    std::string b;
    MyClass c;
} // в этот момент сначала будет разрушен объект c, затем b, затем все строки в a, и наконец сам вектор a.

Если перейти к указателям, то вы оказались правы: только память, занимаемая самим указателем (обычно это 4-байтное целое число), будет автоматически освобождена при выходе из области видимости. Ничего не произойдет с памятью, на которую указывает указатель, если вы явно не используете delete (независимо от того, находится ли этот указатель в векторе или нет). Если у вас есть класс, который содержит указатели на другие объекты, вам может потребоваться освободить их в деструкторе (в зависимости от того, является ли этот класс "владельцем" этих объектов). Обратите внимание, что в C++11 появились классы указателей (называемые умными указателями), которые позволяют вам работать с указателями аналогично "обычным" объектам:

Пример:

{
    std::unique_ptr<std::string> a = std::make_unique<std::string>("Hello World");
    function_that_wants_string_ptr(a.get());
} // в этом случае a вызовет delete для своего внутреннего указателя на строку и затем будет разрушен
0

Это зависит от ситуации.

Если у вас есть вектор значений std::vector<MyClass>, то деструктор вектора вызовет деструктор для каждого экземпляра MyClass, находящегося в векторе.

Если у вас есть вектор указателей std::vector<MyClass*>, то вы несете ответственность за удаление экземпляров MyClass.

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

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь