2016-11-29 4 views
1

Вот код:Удаление массива объектов

class A { 
    private: 
     int *anArr; 
     int id; 
    public: 
     A() { 
      id = 0; 
      anArr = new int[10]; 
     } 
     A(int i) { 
      id = i; 
      anArr = new int[10]; 
     } 
     ~A() { 
      delete[] anArr; 
      std::cout << "Class A id : " << id << " destructor" << std::endl; 
     } 
    }; 

    class B { 
    private: 
     A *anArr; 
    public: 
     B() { 
      anArr = new A[10]; 
     } 
     ~B() { 
      std::cout << "Class B destructor" << std::endl; 
      delete[] anArr; 
     } 
     void changeAnElement() { 
      anArr[2] = A(1); 
      anArr[2] = A(2); 
     } 
    }; 

    int main() 
    { 
     B b; 
     b.changeAnElement(); 

     return 0; 
    } 

Выход:

Class A id : 1 destructor 
Class A id : 2 destructor 
Class B destructor 
Class A id : 0 destructor 
Class A id : 0 destructor 
Class A id : 0 destructor 
Class A id : 0 destructor 
Class A id : 0 destructor 
Class A id : 0 destructor 
Class A id : 0 destructor 
// Gives heap error here 

Так что, если я не ошибаюсь, когда я изменить элемент массива объекта он не вызывает деструктор , Мой первый вопрос: что происходит со старым объектом в измененном индексе? Является ли массив в нем утечкой? Я думал, что мне нужно сам вызвать деструктор, чтобы предотвратить утечку памяти, но он дает ошибку кучи. Второй вопрос: я получаю ошибку кучи (Expression: _CrtlsValidHeapPointer(block)) при вызове деструктора измененного объекта. Я понятия не имею, почему это прекрасно работает для созданных в конструкторе. Спасибо!

+1

Обратите внимание: если вы выполняете ручное управление памятью в классе, вам необходимо следовать правилу 3 или 5. – NathanOliver

+1

Я бы предположил, что 'anArr [0] = A (1)' эквивалентен 'anArr [0] .operator = (A (1)) ', который построил бы новый' A' с 'id = 1', вызовет конструктор копирования' anArr [0] 'с этим' A, id = 1', затем уничтожить 'A, id = 1'. Реализация по умолчанию для 'A :: operator =' не будет управлять вашей памятью для вас, поэтому вы просачиваетесь. Решение: Внесите конструктор копирования или используйте 'std :: vector' /' std :: array' – lcs

+0

@NathanOliver спасибо, я никогда не слышал о них. –

ответ

2

Мой первый вопрос: что происходит со старым объектом в измененном индексе?

Объект в массиве никогда не идет нигде. «Старый» объект остается в этом индексе. Вы вызываете оператор присваивания этому объекту. Оператор присваивания модифицирует объект.

Имеет ли массив в нем утечку?

Массив, на который указывает объект, указывающий перед назначением, утечка, да.

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

Вы создали объект с new[], так что вам нужно позвонить delete[], который действительно вызывает деструкторы.

, но он дает ошибку кучи

Это потому, что вы забыли следовать rule of 3 (or of 5).

anArr[2] содержит тот же указатель, содержащий временный A(2), но так как деструктор временного уже запущено, оно уже удалено массив и деструктор anArr[2] затем пытается удалить его снова. Это одна из вещей, которые нельзя делать.


Выводы:

  • При выполнении ручного управления памятью, следуют правилу 3
  • Не делать ручное управление памятью. Вместо этого используйте std::vector или std::array.
1

Что происходит со старым объектом при изменении индекса?

Переустановлено. В C++, эта линия

anArr[2] = A(1); 

делает новый временный объект A(1), присваивает это значение в существующий объект anArr[2] и уничтожает временный объект. anArr[2] - это тот же объект во всем, изменяется только его значение. Поскольку он не был вновь создан, он также не уничтожается на этом этапе. Но обратите внимание, что временный объект был удален и удалил это совершенно новое int[10], что anArr[2]считает (ошибочно), что он владеет.

Когда это значение является указателем на существующие ресурсы, которые необходимо освободить, вам необходимо написать пользовательский оператор присваивания, A::operator=(const A&). В «Правиле трех» говорится, что в большинстве случаев, когда вам нужен собственный деструктор, пользовательский конструктор копирования или пользовательский оператор назначения копирования, вам также нужны оба других. (Поскольку C++ 11, переместить конструктор и назначение перемещения добавляются в этот список, делая «Правило пяти»).

Смежные вопросы