C ++ malloc / realloc странное поведение - PullRequest
0 голосов
/ 11 мая 2018

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

template <class T>
dynArr<T>::dynArr()
{
rawData = malloc(sizeof(T) * 20); //we allocate space for 20 elems
memset(this->rawData, 0, sizeof(T) * 20); //we zero it!
currentSize = 20;
dataPtr = static_cast<T*>(rawData); //we cast pointer to required datatype.
}

И эта часть работает - итерация по циклу с разыменованием, dataPtr прекрасно работает.Нули.

Тем не менее, перераспределение ведет себя (на мой взгляд) по крайней мере немного странно.Сначала вы должны взглянуть на код перераспределения:

template <class T>
void dynArr<T>::insert(const int index, const T& data)
{

    if (index < currentSize - 1)
    {
        dataPtr[index] = data; //we can just insert things, array is zero-d
    }

    else
    {
        //TODO we should increase size exponentially, not just to the element we want

        const size_t lastSize = currentSize; //store current size (before realloc). this is count not bytes.

        rawData = realloc(rawData, index + 1); //rawData points now to new location in the memory
        dataPtr = (T*)rawData;
        memset(dataPtr + lastSize - 1, 0, sizeof(T) * index - lastSize - 1); //we zero from ptr+last size to index

        dataPtr[index] = data;
        currentSize = index + 1;
    }

}

Простой, мы перераспределяем данные до индекса + 1 и устанавливаем еще ненулевую память на 0.

Что касается тестаСначала я вставил 5 в позицию 5 в этом массиве.Ожидаемая вещь произошла - 0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

Тем не менее, вставка чего-то другого, например вставки (30,30), вызывает у меня странное поведение:

0, 0, 0, 0, 0, 5, 0, -50331648, 16645629, 0, 523809160, 57600, 50928864, 50922840, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30,

Какого черта, я чего-то здесь не понимаю??не должен ли realloc учитывать все 20 ранее установленных байтов памяти?Какое колдовство здесь происходит.

1 Ответ

0 голосов
/ 11 мая 2018

Задача 1:

Вы используете неправильный размер при вызове realloc. Измените его на:

rawData = realloc(rawData, sizeof(T)*(index + 1)); 

Если rawData относится к типу T*, предпочтите

rawData = realloc(rawData, sizeof(*rawData)*(index + 1)); 

Задача 2:

Последний срок следующего неверен.

memset(dataPtr + lastSize - 1, 0, sizeof(T) * index - lastSize - 1); 

Вам необходимо использовать:

memset(dataPtr + lastSize - 1, 0, sizeof(T) * (index - lastSize - 1));
                               //  ^^              ^^
                               // size      *  The number of objects 

Задача 3:

Назначение dataPtr с использованием

dataPtr[index] = data;

является проблемой, когда память получается с использованием malloc или realloc. malloc семейство функций возвращает только сырую память. Они не инициализируют объекты. Присвоение неинициализированных объектов является проблемой для всех типов, отличных от POD.

Задача 4:

Если T имеет тип с виртуальными функциями-членами, использование memset для обнуления памяти, скорее всего, приведет к проблемам.


Предложение по устранению всех проблем:

Будет гораздо лучше использовать new и delete, поскольку вы находитесь на земле C ++.

template <class T>
dynArr<T>::dynArr()
{
   currentSize = 20;
   dataPtr = new T[currentSize];
   // Not sure why you need rawData
}

template <class T>
void dynArr<T>::insert(const int index, const T& data)
{
   if (index < currentSize - 1)
   {
      dataPtr[index] = data;
   }

   else
   {
      const size_t lastSize = currentSize;
      T* newData = new T[index+1];
      std::copy(dataPtr, dataPtr+lastSize, newData);
      delete [] dataPtr;
      dataPtr = newData;
      dataPtr[index] = data;
      currentSize = index + 1;
   }
}

Обратите внимание, что предлагаемое изменение будет работать, только если T является конструируемым по умолчанию.

Это также решит проблемы 3 и 4, описанные выше.

...