Деструкторы в C++ с использованием векторов и указателей
У меня есть некоторые вопросы касательно управления памятью в C++. Я знаю, что в деструкторах нужно освобождать память для всего, что было создано с помощью new, а также закрывать открытые потоки файлов и другие потоки. Однако у меня есть сомнения относительно других объектов в C++:
Автоматическое разрушение: Автоматически ли уничтожаются объекты
std::vectorиstd::string?Векторы указателей: Рассмотрим следующий код:
std::vector<myClass*>Если у меня есть вектор указателей на объекты класса
myClass, что произойдет, когда будет вызван деструктор вектора? Будет ли автоматически вызван деструкторmyClassдля каждого объекта, или только уничтожится сам вектор, а объекты, на которые он указывает, останутся в памяти?Указатели внутри классов: Что произойдет, если у меня есть указатель на другой класс внутри одного класса, например:
class A { ClassB* B; }Если класс
Aбудет уничтожен в какой-то момент в коде, будет ли также уничтожен классB, или уничтожится только указатель, а классBостанется где-то в памяти?
Спасибо за помощь!
5 ответ(ов)
Да, они уничтожаются автоматически (при условии, что членские переменные не являются указателями на std::vector и std::string).
Если у вас есть что-то вроде std::vector, что происходит, когда вызывается деструктор вектора? Вызывается ли автоматически деструктор вашего класса? Или уничтожается только вектор, а все объекты, которые он содержит, остаются в памяти?
Если это vector<MyClass>, то все объекты, содержащиеся в векторе, будут уничтожены. Если это vector<MyClass*>, то все объекты должны быть явным образом удалены с помощью delete (при условии, что класс, в котором находится вектор, владеет этими объектами). Третья альтернатива — это использовать вектор умных указателей, например, vector<shared_ptr<MyClass>, в этом случае элементы вектора не нужно будет явно удалять.
Что произойдет, если внутри класса есть указатель на другой класс?
Указатель B должен быть явно удален с помощью delete. Опять же, можно использовать умный указатель для управления уничтожением B.
Когда вы работаете с динамически выделенной памятью в C++ (например, когда вы используете оператор new), вам нужно заботиться о её освобождении, чтобы избежать утечек памяти.
В приведённом вами примере класса Myclass используется динамический массив символов, который выделяется с помощью оператора new. Важно правильно освобождать эту память в деструкторе класса, чтобы избежать утечек.
Пример:
class Myclass {
private:
char* ptr; // Указатель на динамически выделенный массив
public:
// Деструктор, освобождающий память
~Myclass() {
delete[] ptr; // Освобождаем память
}
};
Таким образом, вам нужно беспокоиться о том, чтобы добавить delete или delete[] (в зависимости от того, как вы выделяли память) в деструктор, чтобы гарантировать, что память будет освобождена при уничтожении объекта. Если вы не сделаете этого, вы можете столкнуться с утечками памяти, что повредит стабильности и производительности вашего приложения.
Если объекты находятся в автоматическом хранилище, то да. Вы можете создать указатель на std::string, используя std::string* s = new std::string, в этом случае вы должны самостоятельно освобождать память с помощью delete.
Ничего особенного, вы должны вручную освобождать память, которую вы выделили (при помощи new).
Если вы выделили b с помощью new, то вам следует явно уничтожить его в деструкторе.
Хорошее правило: используйте delete/delete[] для каждого new/new[], который есть в вашем коде.
Лучшее правило: используйте RAII и предпочитайте умные указатели вместо "сырых" указателей.
Это зависит от контекста. 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 для своего внутреннего указателя на строку и затем будет разрушен
Это зависит от ситуации.
Если у вас есть вектор значений std::vector<MyClass>, то деструктор вектора вызовет деструктор для каждого экземпляра MyClass, находящегося в векторе.
Если у вас есть вектор указателей std::vector<MyClass*>, то вы несете ответственность за удаление экземпляров MyClass.
Что касается вопроса о том, что происходит, если внутри класса есть указатель на другой класс, то экземпляр ClassB останется в памяти. Возможные способы, чтобы деструктор ClassA выполнил эту задачу за вас, — это сделать B членом класса или использовать умный указатель.
Использование `destructor = delete;` в C++
Как удалить элемент из std::vector<> по индексу?
`unsigned int` против `size_t`: когда и что использовать?
Какова разница между "new", "malloc" и "calloc" в C++?
Что означает && в конце сигнатуры функции (после закрывающей скобки)?