2015-05-11 3 views
1

Следующий код приводит к ошибке с присвоением. Кроме того, сообщение об ошибке указывает, что обнаружено повреждение кучи.Обнаружено повреждение кучи - класс с указателями

class A { 
    int* a; // dynamic array of ints 
    A() {}; 
    A(int size) { 
     a = new int[size]; 
    } 
    ~A() { 
     delete [] a; 
     a = nullptr; 
    } 
} 

*** in code somewhere *** 
int size = 5; 
A temp = A(size); 
+4

Ознакомьтесь с правилом 3 (правило 5 для 'C++ 11'). См. Мой ответ здесь для множества способов исправления. http://stackoverflow.com/questions/17840579/scalar-deleting-destructor-issue/17840926 – Chad

ответ

5

Причина ошибки является:
Врут ИНД = А (размер);
Эта строка вызывает: конструктор копирования

  1. A в, здесь: ТЕмп = A (размер); Проблема заключается в том, что это создает неглубокую копию, поскольку она использует конструктор копии по умолчанию, и у нас есть указатель в классе, который нуждается в глубокой копии!
  2. A параметрированный конструктор, здесь: A (размер);
  3. A destructor, который удалит наш указатель, созданный A temp и null it.

Затем, когда температура переменная выходит из области видимости, его деструктор будет называться снова, и, таким образом, привести к Assertation потерпеть неудачу.

Решение:

1. Врет ИНД (размер);
вместо A temp = A (размер);

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

Другая поправка по Marco Costa
Это лучше инициализировать к nullptr в конструктор по умолчанию.

Другая поправка по user4581301
деструктор должен проверить, если является nullptr, перед удалением.

Дополнительные показания:
1. Why aren't pointers initialized with NULL by default?
2. Rule-of-Three becomes Rule-of-Five with C++11?предложенные Чад
3. scalar deleting destructor issueпредложил Чад

+4

Кроме того, вы должны действительно инициализировать a до nullptr в конструкторе по умолчанию. –

+1

И проверить a для null в деструкторе перед удалением – user4581301

1

Как указано другими, необходимо следовать правилу 3 (или 5).

Однако есть еще одна проблема с вашим классом, и вы не записываете количество элементов. Это важно, если вы хотите правильно реализовать эти функции. Нет стандартного способа извлечения количества элементов, которые вы использовали для вызова new[], поэтому вам нужно записать это значение в качестве члена.

class A { 
    int* a; 
    int aSize; // records the number of elements. 
    A() : aSize(0), a(nullptr) {} 
    A(int size) : aSize(size) 
    { a = new int[size]; } 

//... 
}; 

Необходимо добавить члена размера в свой класс, иначе вы не сможете реализовать требуемые функции копирования.