Удаление массива приводит к ошибке EXC_BAD_ACCESS - PullRequest
1 голос
/ 24 января 2012

У меня есть класс Foo, определенный следующим образом:

class Foo
{
  public:
    Foo(int num);
    Foo(const Foo& other);
    ~Foo();

    Foo& operator=(const Foo& other);
    ...

  private:
    string *fooArray;
    void clearMemory();
    ...
}

Foo::Foo(int num)
{
    fooArray = new string[num];
}

Foo::Foo(const Foo& other)
{
    *this = other;
}

Foo::~Foo()
{
    clearMemory();
}

Foo& operator=(const Foo& other)
{
    clearMemory();
    fooArray = new string[other.size]; // size is a private variable
    memcpy(fooArray, other.fooArray, other.size * sizeof(string));
}

void Foo::someOtherFooFuncion(int newNum)
{
    clearMemory(); // crash with Visual Studio, does not crash with g++, but g++ also
                   // crashes when destructor is called
    fooArray = new string[newNum];
}

void Foo::clearMemory()
{
    if(fooArray != NULL)
    {
        delete[] fooArray; // sometimes it crashes here with g++; it always crashes when
                           // compiling in Visual Studio
        fooArray = NULL;
    }
}

Как отмечается в комментариях к коду, он иногда дает мне сбои. Я попытался выполнить шаги в GDB, я дошел до

destructing Foo:
@0x7fff5fbff9b0
$26 = {
  fooArray = 0x1001009d8, 
  ...
}

И тогда delete[] fooArray достигается, и вдруг

Foo(49858) malloc: *** error for object 0x100100990: pointer being freed was not allocated

Понятия не имею, откуда взялся 0x100100990.

Я понимаю, что код очень неполный, но я действительно даже не знаю, с чего начать поиск ошибки, и хотел бы дать несколько советов о том, какие возможные условия могут вызвать ошибки delete[].

EDIT

Добавлены c'tor, d'tor и оператор присваивания. Я не на ПК, поэтому код может быть не на 100% точным. Присвоение значений для fooArray и доступ к ним работает очень хорошо.

Кроме того, я был бы очень признателен за общий список проблем, которые потенциально могли бы вызвать delete[] выдачу ошибки, чтобы я мог хотя бы иметь представление о том, где искать в коде.

РЕДАКТИРОВАТЬ 2 :

Итак, я последовал совету Xeo по использованию std::uninitialized_copy, теперь код работает нормально и компилируется под g ++. Деструктор также отлично работает в Visual Studio, но каким-то образом удаление fooArray в someOtherFooFuncion приводит к сбою.

Есть еще идеи?

Ответы [ 3 ]

2 голосов
/ 24 января 2012

Убедитесь, что вы определили конструктор копирования и оператор присваивания. Им нужно будет выделить память для fooArray. Если вы не определили копию ctor и operator=, компилятор сгенерирует их для вас. Однако, сгенерированные компилятором просто скопируют указатель fooArray, что может привести к двойному deletes.

Если вы уже определили их, добавьте соответствующий код к вашему вопросу.

edit: Я вижу, что ваш конструктор копирования не выделяет память, а ваш оператор присваивания использует memcpy(). И то, и другое может вызвать проблемы.

1 голос
/ 25 января 2012

Не используйте memcpy в C ++

Не могу не подчеркнуть этот момент.Когда memcpy объект класса в C ++ (точнее, не POD), вы нарушаете ' инварианты этого класса , определенные его конструкторами, поскольку вы обходите именно их.Каждый раз, когда вы memcpy aa std::string класс, вы получаете новый объект, ссылающийся на той же памяти как другой объект.Вы получите двойное удаление с этим, что вызывает ваш сбой.

Используйте std::uninitialized_copy из <algorithm>, как это:

//                      src_begin             src_end           dest
std::uninitialized_copy(other.array, other.array + other.size, array);

(не проверено, потому что я пишу этоот моего iPod)

Или даже лучше, просто используйте std::vector вместо необработанной памяти.Вам больше не понадобится деструктор и копия оператора ctor / назначений.

1 голос
/ 24 января 2012

Если вы определяете конструктор по умолчанию, вы должны инициализировать fooArray в NULL, в противном случае fooArray может указывать на случайную ячейку памяти, которая затем подвергается delete[].

...