2013-10-25 3 views
1

Я пытаюсь создать динамически выделенный массив, который при заполнении создает новый массив, достаточно большой для хранения всего и копирует все значения из старого массива в новый массив. Я выполняю функцию append, которая при вызове динамически выделяет новый массив с tmp, указывающим на него, а затем перемещает значения из arr [i] в ​​tmp [i]. Тем не менее, мне интересно, нужно ли мне удалять tmp, когда я закончил с ним? Потому что, когда я пытаюсь распечатать содержимое массива без удаления tmp, он печатает просто отлично, но когда я удаляю tmp, вещи просто начинают становиться странными, а содержимое больше не печатается так, как должно. Вот мой код:Создание динамически выделенного массива

ArrayList::ArrayList(int initsize): last(0), size(initsize), origsize(initsize) 
{ 
    arr = new int[size]; 
} 

ArrayList::ArrayList() 
{ 
    last = 0; 
    size = 16; 
    origsize = 16; 
    arr = new int[size]; 
} 

void ArrayList::append(int value) 
{ 
    if (last<size) { 
     arr[last] = value; 
    } 

    last++; 

    if (last == size) { 

     int* tmp = new int[size+origsize]; 
     int i = 0; 

     for (i=0; i<(size+origsize); i++) 
      tmp[i] = arr[i]; 

     size = size+origsize; 
     arr = tmp; 
     arr[last] = value; 

     //delete tmp; 
    } 
} 
+0

Просто убедитесь, что вы удалили в нужном месте. Ваш комментарий удаляет 'tmp', но я думаю, вы должны удалить' arr' прямо перед строкой 'arr = tmp'. – Sjlver

+0

... Я предполагаю, что это академический подход и поэтому бросает всю вещь в пользу «std :: vector », о чем не может быть и речи. – WhozCraig

ответ

2

Проблема здесь:

for (i=0; i<(size+origsize); i++) { 

     tmp[i] = arr[i]; 

    } 

обр имеет длину «размер», но вы пытаетесь получить доступ к элементам за ним. Это приведет к неопределенному поведению.

IMO, вы не должны пытаться изменить размер массива в своей программе. Если вы хотите контейнер с динамическим размером, используйте вместо него std :: vector.

EDIT: Как уже отмечалось, если это по академической причине, то вы можете изменить свой код примерно следующее:

void ArrayList::append(int value) 
{ 
    if (last<size) { 
     arr[last] = value; 
     last++; 
    } else { // last shall be equal to size. 

     int* tmp = new int[size+origsize]; 
     int i = 0; 

     for (i=0; i<(size); i++) // delete + originalsize 
      tmp[i] = arr[i]; 

     size = size+origsize; 
     int* newTemp = arr; // make a new pointer point to where arr was pointing 
     arr = tmp;   // make arr point to where tmp was pointing. 
     //tmp = newTemp; // You do not need this statement. 
     arr[last] = value; 
     last++; 
     delete [] newTemp; // delete the old array memory block 
    } 
} 
+0

Да, я бы предпочел использовать это, я уверен (мы не узнали об этом в классе), но наш профессор специально хочет, чтобы мы ... сделали это сами по себе, я думаю, чтобы научить нас некоторым урокам, которые я делаю не понимать. Он не любит нас, используя какие-либо функции, которые мы не создали ourselvs. – FrostyStraw

+0

Я думаю, что он пытается реализовать ArrayList, который под капотом просто использует массивы и изменяет их размеры. –

2

Ваш обр является теперь TMP. Я имею в виду, что они оба указывают на новый массив. И вам нужно удалить старый. Do

int* old = arr; 
arr = tmp; 
delete [] old; 
arr[last] = value; 
+0

Если я правильно это читаю ... когда вы удаляете arr, вы удаляете старый массив. Затем вы спрашиваете tmp, чтобы указать на то, о чем указывал arr..which в этот момент ничего нет, поскольку arr был удален ... – FrostyStraw

+0

Мой плохой. Ред. –

+0

Так что, если я просто удалю старый, я просто удалю указатель с именем old. Но для удаления фактического массива, на который указывает старый, мне нужно удалить [] old? – FrostyStraw

0

Новый массив указывает на старый.

Так что в вашем коде (withou модификаций), вы не можете удалить обр

0

Вы определенно должны удалить TMP, потому что, так как вы объявили его в качестве указателя с помощью *. Он не будет автоматически освобожден после того, как вы покинете область действия (оставив следующую)) и вызовет утечку памяти. Полезный пост here о указателе и о том, как объявить его в кучу и требует, чтобы он был удален вручную. Поскольку вы пытаетесь создать динамический массив здесь. Я думаю, вы хотите, чтобы arr был указателем, а не tmp. Выезд this c++ tutoriall

0

Вы используете new и delete, что является C-ish. В C++ вы должны доверять существующим средствам для обработки памяти для вас. Мы могли бы использовать std::vector, хотя это может помешать упражнению; вместо этого я предлагаю использовать std::unique_ptr.

class ArrayList { 
public: 
    ArrayList(); 

    explicit ArrayList(size_t i); 

    void append(int i); 

private: 
    size_t last;     // position to append to 
    size_t size;     // current size of the array 
    std::unique_ptr<int[]> array; // actual array of data 
}; // class ArrayList 

Примечание: вместо использования origsize, мы можем удвоить пропускную способность в каждом расширении, таким образом, получить «амортизируется постоянную» сложность для append.

// We first need a creation function for raw memory: 
std::unique_ptr<int[]> allocate(size_t n) { 
    return std::unique_ptr<int[]>(new int[n]); 
} 

// Now, the default constructor 
ArrayList::ArrayList(): last(0), size(16), array(allocate(size)) {} 

// And the user constructor 
ArrayList::ArrayList(size_t i): last(0), size(i), array(allocate(size)) {} 

С этим из пути, давайте сосредоточимся на append:

void ArrayList::append(int e) { 
    if (last >= size) { // need to reallocate 
     std::unique_ptr<int[]> neo = allocate(size*2); 

     for (size_t i = 0; i < size; ++i) { 
      neo[i] = array[i]; 
     } 

     size *= 2; 
     swap(neo, array); 
    } // reallocation 

    array[last] = e; 
    ++last; 
} 

Как это отличается от кода:

  1. При копировании из одного массива в другой, Я копирую только size элементов (вы читали за пределами поля)
  2. Я не обрабатываю память вручную, вместо этого Я откладываю обработку памяти до std::unique_ptr.
  3. Нет необходимости перераспределять после того, как вы вставили e в append, вы можете просто подождать, пока у вас не будет места для этого.
  4. Использование амортизируемой постоянной сложностью для append является более эффективным
Смежные вопросы