динамическое распределение памяти, члены-указатели и деструкторы

Я написал следующий фиктивный класс, чтобы понять, как работает конструктор копирования, оператор присваивания копии и деструктор:

#include <string>
#include <iostream>

class Box {

public:
// default constructor
Box(int i=10,const std::string &t=std::string()) : a(i),s(new std::string(t)) {}
// copy constructor
Box(const Box &other) { a=other.a; s=new std::string(*other.s); }
// copy assignment operator
Box &operator=(const Box &other) { a=other.a; s=new std::string(*other.s); }
// destructor
~Box() { std::cout<<"running destructor num. "<<++counter<<std::endl; }
int get_int() { return a; }
std::string &get_string() { return *s; }
private:
int a;
std::string *s;
static int counter;

};

int Box::counter=0;

Я использую этот тип класса в своем коде, чтобы проверить, как он работает, но я думал о последствиях в уничтожении объектов, которые имеют член встроенного типа указателя:

#include "Box.h"
using namespace std;

int main()
{
Box b1;
Box b2(2,"hello");
cout<<b1.get_int()<<" "<<b1.get_string()<<endl;
cout<<b2.get_int()<<" "<<b2.get_string()<<endl;
Box b3=b1;
Box b4(b2);
cout<<b3.get_int()<<" "<<b3.get_string()<<endl;
cout<<b4.get_int()<<" "<<b4.get_string()<<endl;
b1=b4;
cout<<endl;
cout<<b1.get_int()<<" "<<b1.get_string()<<endl;
{
Box b5;
}  // exit local scope,b5 is destroyed but string on the heap
// pointed to by b5.s is not freed (memory leak)
cout<<"exiting program"<<endl;
}

Этот указатель инициализируется в конструкторе для указания (всегда новой) динамически выделяемой памяти в свободном хранилище. Таким образом, когда вызывается деструктор, члены уничтожаемого объекта уничтожаются в обратном порядке. Правильно ли в этом случае, что уничтожаются только объекты типа int и pointer, и в результате возникает утечка памяти (строка в куче не освобождается)?

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

2

Решение

Каждый раз, когда вы вызываете новый, вы должны удалить его (кроме общих указателей).

Таким образом, вы должны удалить строку в деструкторе.

Оператор присваивания работает с существующим экземпляром, поэтому вы уже создали s и вам не нужно создавать новую строку для s.

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

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

4

Другие решения

Имейте в виду, что распределение происходит на основе построения, копирования и на удивление при условии назначения

Выделение происходит в деструкторе и условно по назначению

Состояние, за которым нужно следить:

x = x;

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

  Box(int i=10,const std::string &t=std::string()) : a(i),s(new std::string(t)) {}
// copy constructor
Box(const Box &other) { cp(other); }
// copy assignment operator
Box &operator=(const Box &other) {
if (&other != this)  // guard against self assignment
{
rm();
cp(other);
}
return *this;
}
// destructor
~Box() { rm();  }
private:
void cp(const Box &other) {a=other.a; s=new std::string(*other.s);
void rm() {
std::cout<<"running destructor num. "<<++counter<<std::endl;
delete s;    // prevents leaks
}
2

Один из возможных способов справиться с неназванными динамически распределенными элементами — сохранять их в контейнере каждый раз, когда они создаются (в объекте, функции и т. Д.), А затем запускать for цикл в вашем деструкторе с delete оператор, за которым следуют элементы контейнера.

Вы можете сделать это с вектором:

vector <string*> container;

и вы можете использовать его следующим образом:

// define it in the private members of your class
vector <string*> container;

// use it when you create the string
container.push_back(new dynamicallyAllocatedObject);

// free memory in the destructor
for(auto it = container.begin(); it != container.end(); ++it) delete *it;
0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector