2013-12-02 6 views
1

Я недавно столкнулся с проблемой с некоторым кодом, который я написал на C++, который я не мог найти для решения. На первый взгляд проблема казалась очень простой, но по какой-то причине программа выдает ошибку, и я не могу объяснить, почему. Я не собираюсь копировать-вставить исходный код, в котором я столкнулся ошибка (так как это слишком громоздкие), но вот упрощенная версия этого, который обладает точно таким же поведением и в том же контексте:Ошибка отладки при отладке при удалении объекта

#include<vector> 
using namespace std; 
class A_class 
{ 
    bool *heap_space; //can be any type of pointer 
public: 
    A_class() { heap_space = new bool[4]; } 
    A_class(const A_class&) { heap_space = new bool[4]; } 
    ~A_class() { delete[] heap_space; } 
}; 
void main() 
{ 
    vector<A_class> ObjArr(5); 
    vector<A_class>::iterator iTer = ObjArr.begin() + x; 
    //where x can be any number from 0 to 3 
    ObjArr.erase(iTer); 
} 

Я знаю, что код выглядит нереально простым, но я просто не могу понять причину заброшенного исключения. Код будет вызывать «Ошибка отладки»! сообщение во время выполнения с «Выражение: _BLOCK_TYPE_IS_VALID (pHead-> nBlockUse)» каждый раз, когда я пытаюсь запустить его.

Также может быть полезно упомянуть, что сообщение не появляется сразу во время метода стирания контейнера. Он появляется только после того, как вектор выходит за рамки. Таким образом, я продолжал исправлять ошибку с помощью различных методов, добавляя код до того, как вектор выходит из области действия (например, повторно вставляя новый элемент сразу после стирания), но без успеха. Кроме того, после небольшого эксперимента я узнал, что сообщение появляется только после стирания чего-либо, кроме последнего элемента вектора (ObjArr.end() - 1). Если последний элемент вектора является стираемым, то, по-видимому, ничего плохого не происходит. Надеюсь, эти подсказки помогли. Если кто-нибудь знает, почему это происходит, объясните мне это. Я уверен, что я просто делаю ошибку новобранец, так как это кажется таким легким для понимания, но я не могу.

Код выше был составлен с использованием Visual Studio 2013 под Windows 7.

+0

Для справки, этот код отлично работает на моем компьютере (x64 linux) и на ideone (http://ideone.com/8MPbHG) – Xymostech

+1

Вам необходимо предоставить оператор присваивания. – juanchopanza

ответ

2

Интересно, что это происходит потому, что вы не предоставили оператор присваивания. Зачем вам это нужно? Ну давайте подумаем о векторе. Векторный объект имеет указатель на массив из 5 A_class. Они построены по умолчанию, и это не проблема, поскольку вы определили его. Теперь стираем:

A_class } 
A_class } 
A_class }-- Erase one of these 
A_class } 
A_class } 

Интересно, что мы не видим проблемы, если мы удаляем последний, только если удалить один из индексов 0 до 3. Почему? Ну, когда мы удаляем, скажем, индекс 2, мы получим его:

A_class 
A_class 
-- empty space with size = sizeof(A_class) 
A_class 
A_class 

Чтобы согласовать это пространство, в конце стирает, std::vector использует оператор присваивания для подправить массив. Таким образом, index[2] = index[3], index[3] = index[4]. Теперь, поскольку вы не объявили оператора присваивания, он будет использовать значение по умолчанию, которое включает в себя удаление index[4]. Это плохо, потому что index[4] даст index[3] свой указатель затем удалить его, в результате чего в этом:

A_class // heap_space okay 
A_class // heap_space okay 
A_class // heap_space okay 
A_class // heap_space deleted! will error when deconstructed 

Так что теперь, когда мы выходим, мы удалим index[3] и все взорвется!

Добавляя оператор присваивания, который использует swap, мы можем решить эту проблему:

class A_class 
{ 
public: 
//... 
    // note the byval argument 
    A_class& operator=(A_class other) { 
     std::swap(this->heap_space, other.heap_space); 
     return *this; 
    } 
//... 
} 
+0

Это сделало трюк для меня. Благодаря! –

0

Когда вы ObjArray.erase() объект, то std::vector<A_class> заполнит полученный разрыв.Для этого он переместит более поздние объекты на один объект вперед: он присваивает каждому объекту до тех пор, пока не будут назначены все объекты, и, наконец, он уничтожит последний элемент, в результате получится delete[], в котором находится heap_space объекта. Обратите внимание, однако, поскольку у вас нет назначения копирования или перемещения, только указатель heap_space был назначен, то есть после erase() объект, последний объект находится в плохом состоянии: он содержит указатель на уже выделенный массив delete[]bool , Когда ObjArray позже выходит из сферы действия, все объекты уничтожаются и происходит двойное delete[]. Здесь вы получите наше отладочное утверждение.

Самый простой способ решить проблему заключается в создании задания копирования:

A_class& A_class::operator= (A_class other) { 
    this->swap(other); 
    return *this; 
} 
void A_class::swap(A_class& other) { 
    std::swap(this->heap_space, other.heap_space); 
} 

выше реализация рычаги три операции, которые обычно требуется во всех классах, которые на самом деле нужно назначение копирования:

  1. Конструктор копирования принимает случай создания новой копии назначенного аргумента при создании аргумента, переданного оператору присваивания.
  2. Метод swap(), который обменивается содержимым текущего объекта с временной копией в аргументе.
  3. Деструктор, который освобождает память исходной левой части, поскольку она была помещена во временную копию.
Смежные вопросы