Использование функции удаления внутри

У меня проблема с вызовом функции удаления внутри. Когда я выделяю память с помощью новой внутренней функции, кажется, что она работает, но удаление ранее выделенной памяти вызывает выброс std::bad_alloc. Возможно ли это, или я могу освободить память только под «а» внутри основного?

#include <iostream>

using namespace std;

int size = 5;

void alloc (int* t, char**& a) {
  t = new int [size];
  a = new char* [size];
  for (int i = 0; i < size; ++i)
    a[i] = new char [size];
  cout << "allocated\n";
}

void realloc (char**& a) {
  for(int i = 0; i < size; ++i)
    delete [] a[i];
  delete [] a;
  cout << "deleted\n";
  a = new char* [size];
  for (int i = 0; i < size+5; ++i)
    a[i] = new char [size+5];
  cout << "allocated\n";
}
void fillArray (char** a) {
  for (int i = 0; i < size; ++i) {
    for (int j = 0; j < size; ++j) {
      a[i][j] = '.';
    }
  }
}

void printArray (char** a) {
  for (int i = 0; i < size; ++i) {
    for (int j = 0; j < size; ++j) {
      cout << a[i][j];
    }
    cout << endl;
  }
}
int main() {
  int* t;
  char** a;
  alloc(t, a);
  fillArray(a);
  printArray(a);
  size+=5;
  realloc(a);
  fillArray(a);
  printArray(a);
}

person user2614710    schedule 14.12.2013    source источник


Ответы (1)


Вы можете позвонить delete[] откуда угодно. Ваши проблемы куда более прозаичны. У тебя просто ошибка в коде.

Вы выделяете массив длиной size. Затем вы увеличиваете size. Затем вы делаете это:

for(int i = 0; i < size; ++i)
    delete [] a[i];

И поскольку вы уже увеличили size, ваш цикл заканчивается в конце a. Вам нужно использовать то же значение для size, которое использовалось при выделении массива.

Чтобы быть совершенно ясным, следующий поток выполнения:

  • size присваивается значение 5.
  • a выделяется длиной 5.
  • size увеличивается до значения 10.
  • Вы выполняете цикл for от 0 до size-1, то есть от 0 до 9, и вызываете delete[] a[i].

Очевидно, что итерации с 5 по 9 включительно обращаются к элементам a, которые не были выделены. И это неопределенное поведение, и так далее.

Вы можете исправить это, передав новый размер функции realloc в качестве параметра. Что-то вроде этого:

void realloc (char**& a, size_t newsize) {
  for(int i = 0; i < size; ++i)
    delete [] a[i];
  delete [] a;

  size = newsize;
  a = new char* [size];
  for (int i = 0; i < size; ++i)
    a[i] = new char [size];
}

Очевидно, вы не будете изменять size вне этой функции. Вы бы вызвали функцию следующим образом:

realloc(a, size+5);

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

size_t size = 5;

void alloc(char**& a, size_t newsize) {
  size = newsize;
  a = new char*[size];
  for (int i = 0; i < size; ++i)
    a[i] = new char[size];
}

void realloc(char**& a, size_t newsize) {
  for(int i = 0; i < size; ++i)
    delete[] a[i];
  delete[] a;
  alloc(a, size+5);
}

Все это говорит, и если быть совершенно откровенным, вся ваша программа - это катастрофа в процессе создания. Есть много других ошибок, которые я не рассмотрел в этом ответе. Используйте стандартные контейнеры, такие как std::vector и std::string. Стандартные контейнеры будут обрабатывать детали выделения памяти и будут делать это правильно.

person David Heffernan    schedule 14.12.2013
comment
Спасибо, теперь работает нормально. И если можно поинтересоваться, что такого ужасного в моем коде? - person user2614710; 14.12.2013
comment
1. (Ab)использование глобальных переменных. 2. Утечка. 3. Использование int вместо size_t. 4. Использование необработанного распределения, а не контейнеров STL. 5. Параметр с t по alloc, который не может быть использован. Вызывающий не может видеть значение, присвоенное внутри alloc. - person David Heffernan; 14.12.2013
comment
Почему контейнеры STL намного лучше, чем необработанное распределение? А насчет глобальной переменной и неиспользуемой переменной t, эта программа была сделана просто как тест, и я обычно делаю такие вещи, так что вы можете меня простить за это. - person user2614710; 14.12.2013
comment
Известно, что контейнеры STL работают. Ваш код не работает. Контейнеры STL просты в использовании и позволяют создавать компактный и читаемый код. У них есть мощные итераторы. Код, основанный на встроенном необработанном распределении, сложно поддерживать и он может содержать ошибки. Ваш код протекает. Контейнеры STL этого не делают. Контейнеры STL легко компонуются с другим кодом. Ваш код живет на своем собственном острове и не может взаимодействовать ни с чем другим, если только вы не напишете его сами. - person David Heffernan; 14.12.2013