Реализация стирания в динамическом массиве для сбоев строкового типа - PullRequest
0 голосов
/ 09 октября 2019

Я пытаюсь реализовать вектор stl в C ++ для таких типов, как string, int, ulong и т. Д., Используя шаблонный класс. Функция стирания, найденная ниже, отлично работает для всех других типов данных, кроме строки.

template <typename T>
void myArr<T>::erase(ULONG index)
{
    if(index >= count)
        return;
    T* temp_arr = new T[max_count];
    if(index == 0)
    {
        memcpy(temp_arr,(arr+1),(count-1)*sizeof(T));
    }
    else if(index == count-1)
    {
        memcpy(temp_arr,arr,(count-1)*sizeof(T));
    }
    else
    {
        memcpy(temp_arr,arr,(index-1)*sizeof(T));
        memcpy(temp_arr+index,arr+index+1,(count-index)*sizeof(T));
    }
    delete[] arr;
    arr = temp_arr;
    count--;
}

Когда строка имеет тип массива, программа завершается с нарушением доступа к памяти 0x0005. Как справиться с этим для типа данных строки ..?

Ответы [ 2 ]

1 голос
/ 09 октября 2019

Нельзя использовать memcpy на нетривиально копируемых типах. std::string не может быть скопировано тривиально, поэтому вы не можете использовать его на нем.

Вам нужно иметь специальные версии erase для вызова erase в зависимости от типа, который содержит контейнер. Если это тривиальный тип, тогда вызовите версию erase, которая использует memcpy. Если это не так, вызовите версию erase, которая использует цикл for и выполняет простую операцию копирования / перемещения.

0 голосов
/ 09 октября 2019

Нельзя использовать memcpy() для нетривиальных типов, таких как std::string, для которых может потребоваться копирование внутренних данных из одного экземпляра в другой. В этом случае вам нужно скопировать каждый элемент по отдельности, используя его собственный operator=, например:

template <typename T>
void myArr<T>::erase(ULONG index)
{
    if (index >= count)
        return;

    T* temp_arr = new T[max_count];

    // copy elements before the index...
    for(int i = 0; i < index; ++i) {
        temp_arr[i] = arr[i];
    }

    // copy elements after the index...
    for (int i = index + 1; i < count; ++i) {
        temp_arr[i - 1] = arr[i];
    }

    delete[] arr;
    arr = temp_arr;

    --count;
}

. Или лучше, вместо этого вы можете использовать std::copy(), который оптимизирован длякопирование тривиальных типов и «делает правильные вещи» для копирования нетривиальных типов:

template <typename T>
void myArr<T>::erase(ULONG index)
{
    if (index >= count)
        return;

    T* temp_arr = new T[max_count];

    // copy elements before the index...
    std::copy(arr, arr + index, temp_arr);

    // copy elements after the index...
    std::copy(arr + (index+1), arr + count, temp_arr + index);

    delete[] arr;
    arr = temp_arr;

    --count;
}

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

template <typename T>
void myArr<T>::erase(ULONG index)
{
    if (index >= count)
        return;

    // shift elements after the index down one slot...
    std::copy(arr + (index+1), arr + count, arr + index);

    // clear the now-unused last slot of its data...
    arr[count-1] = T();

    --count;
}
...