Проблема деструктора C++ с std:: вектор объектов класса

Я смущен тем, как использовать деструкторы, когда у меня есть std::vector моего класса.

поэтому, если я создам простой класс следующим образом:

class Test
{
private:
 int *big;

public:
 Test ()
 {
  big = new int[10000];
 }

    ~Test ()
 {
  delete [] big;
 }
};

затем в моей основной функции я делаю следующее:

Test tObj = Test();
vector<Test> tVec;
tVec.push_back(tObj);

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

4 ответов


ваша проблема здесь:

Test tObj = Test();

на Test() создает временную Test объект, который затем копируется tObj. В этот момент оба tObj и временный объект иметь big указывает на массив. Затем временный объект уничтожается, который вызывает деструктор и уничтожает массив. Так когда tObj уничтожается, он пытается снова уничтожить уже уничтоженный массив.

далее, когда tVec разрушено, оно разрушит его элементы, таким образом, уже разрушенный массив будет уничтожен еще раз.

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

простое исправление-определить свой класс следующим образом:

class Test
{
private:
 std::vector<int> big;

public:
 Test (): big(10000) {}
};

в этом случае вам не нужно будет определять деструктор, копировать конструктор или оператор присваивания, потому что std::vector<> участник позаботится обо всем. (Но обратите внимание,что это означает, что при копировании экземпляраTest.)


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

Теперь, когда вы возвращаете свой объект в вектор, он неявно копируется с помощью конструктора копирования. Что приводит к двум объектам, указывающим на один и тот же массив ints! Итак, в конце концов, два деструктора пытаются удалить один и тот же массив - BANG.

всякий раз, когда вы определите класс, которому принадлежат члены через указатели*, кроме деструктора you должны также определить конструктор копирования для него. обновление: и оператор присваивания, по той же причине (спасибо @Джеймс :-)

обновление 2: тривиальный способ обойти все эти ограничения-определить статический массив вместо динамически выделенного:

class Test
{
private:
  int big[10000];
  // no need for constructors, destructor or assignment operator
};
рекомендуется использовать std::vector<int> вместо матрица.

* то есть содержит указатели на членов с семантикой владения (спасибо @Steve Jessop за разъяснение)


без конструктора копирования вектор создаст плоскую копию вашего объекта. Это приводит к двум объектам типа Test ссылка на тот же массив big. Первый экземпляр удаляет массив при его уничтожении, а затем второй экземпляр пытается разыменовать удаленный указатель, что является неопределенным поведением.


Test tObj = Test();

это неправильно и должно быть так как он не создает копий:

Test tObj;

Это также создает много копий:

 vector<Test> tVec;
 tVec.push_back(tObj);

поэтому, если вы освободите один массив int, вы освободите все массивы. И следующее удаление не удастся.

что вам нужно-это:

  • использовать конструктор копирования для каждого класса отдельный массив

  • зачем использовать пойнтер?

class Test    
{   
private:  
  int big[10000];    
public:

};

это будет работать нормально.