2014-08-31 3 views
3

У меня был vector<Points*> points; (size: 6 со всеми уникальными Points) в моей программе, в которой я повторял точки, чтобы нарисовать что-то на экране. Однако, согласно моим новым требованиям, я бы увеличил длину вектора до size: 14.Предотвращение двойного удаления указателей

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

while (currentSize < 14){ 
    int rndPoint = getRandomPoint(0, 5); //random index to choose from the vector 
    points->push_back(points[randPoint]); 
} 

В деструкторе класс, когда я для освобождения памяти, я делаю следующее:

for(int i=0;i<points.size(); ++i){ 
    if(points[i] != NULL){ 
    delete (points[i]); 
    } 
} 

Однако, когда я пытаюсь выйти из программы - я получаю ошибку нарушения доступа в контуре (в частности, когда i достигает индекса 6). Когда я уже удалил 6 уникальных точек, используя delete, почему это условие if (points[i] != NULL) приводит к true для i=6,7...13?

+0

Установить 'points [i] = NULL;' после 'delete', это не делается автоматически. Также проверьте, соответствует ли ваш класс [правилу три] (http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three). –

+0

@ πάνταῥεῖ Это не вопрос. –

+0

@ πάνταῥεῖ Этого недостаточно. Некоторые из элементов 'points []' такие же, как и предыдущие, ergo double delete. –

ответ

4

Причина в том, что при удалении другие ссылки на одну и ту же память не установлены на nullptr (или 0, pre C++ 11). Рассмотрим:

int *foo = new int; 
// foo should be non-nullptr now 
int *bar = foo; 
// bar should be non-nullptr now 
delete foo; 
// both foo and bar are still non-nullptr. 

Есть три способа решить вашу конкретную проблему:

  1. Использование std::shared_ptr
  2. Есть отдельный std::vector для уникальных случаях:

    std::vector<Point> unique_points; 
    std::vector<Point*> used_points; 
    
    // create all needed points *once* in unique_points 
    // insert pointers to the points in unique_points into used_points 
    
  3. Просто сделайте копии.

+0

Почему бы не ответить на следующий вопрос @Skaktal, установив элементы в NULL после удаления? Просто было, потому что я не видел этого в вариантах, которые вы указали выше. – user1240679

+0

@ user1240679 Это не устанавливает другие указатели на один и тот же объект в значение null. –

+0

Aha! Таким образом, будет ли такое присвоение быть действительным 'vector * pointList',' pointsList = sharedPointsList', где 'sharedPointsList' -' vector * '. Кроме того, что было бы лучшим способом сделать копии данных, на которые указывает указатель в приведенном выше случае? – user1240679

7

Используйте умный указатель. Если источник вашей программы содержит delete, и он не находится в состоянии deleter для умного указателя, ваша программа не работает. (И почему, черт возьми, вы бы это сделали, а не std::default_deleter?).

Победитель «Лучшей награды Smart Pointer Award 2014» - std::unique_ptr, с почетным упоминанием для std::shared_ptr для тех случаев, когда вы должны просто скопировать указатель.

Правило нуля означает, что вам вряд ли когда-либо понадобится реализовать деструктор/etc самостоятельно, так как вы всегда должны использовать общие классы управления ресурсами для управления им самостоятельно.

+1

Не говоря уже о комбинации 'std :: shared_ptr' и [' std :: weak_ptr'] (http://en.cppreference.com/w/cpp/memory/weak_ptr), который выглядит вполне уместным для управления прецедентом, описанным в OP. –

+1

На самом деле не очень-то полезно найти 'weak_ptr'. Если вы собираетесь платить за пересчет, чтобы разрешить копирование, вы также можете провести 'shared_ptr' подавляющее большинство времени. – Puppy

0

Общий ответ заключается в том, что при использовании динамической памяти у вас есть ПЛАН для очистки.

Один из планов состоит в том, чтобы использовать различные формы стандартных указателей указателей шаблонов библиотеки (как описано выше). Однако есть и другие способы сделать это.

«Лучший» план зависит от типа приложения. Например, когда вы используете некоторые структуры графиков, подсчет ссылок может не работать, если этот метод работает с другими типами структур.

Например, если вы пытаетесь сделать подсчет ссылок, когда у вас есть

A points to B. 
B points to C and D 
C and D points to E 
E points to B 

Это дает следующие эталонные счетчики

B 2 C 1 D 1 E 2

разрушив link A-> B дает эти контрольные количества

B 1 C 1 D 1 E 2

без ссылки на конструкцию, поэтому он никогда не будет удален.

Выберите лучший план для вашей ситуации.

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