C ++ size_t и ptrdiff_t для индексации отрицательных массивов

Мне трудно выбирать между size_t а также ptrdiff_t для типа индекса, который должен иметь возможность хранить отрицательное значение.

Чтобы быть точным, в моем коде мне нужно реализовать массив. Я получаю его длину (в конструкторе) как тип size_tи когда я перегружал [] operator Мне нужно чтобы индекс был типа ptrdiff_t (и не size_t), так как я хочу разрешить отрицательные индексы, как показано в этом примере:

std::size_t length = 50;
MyVector<int> vec(length);
vec[0] = 10;

MyVector<int> vec2 = vec+1;
std::cout << vec2[-1] << std::endl; //should print 10

Проблема, возникающая в связи с указанным дизайном, заключается в том, что диапазон доступных индексов ограничен максимальным значением ptrdiff_tи в некоторых машинах этот верхний предел меньше максимального значения size_t.

то есть std::numeric_limits<std::ptrdiff_t>::max() < std::numeric_limits<std::size_t>::max()

Таким образом, проблема заключается в том, что пользователь может создать массив с размером, превышающим максимальное значение ptrdiff_t (но все еще в диапазоне size_t, конечно), но он не сможет получить доступ к элементам массива, которые превышают максимальное значение ptrdiff_t, потому что их индексы будут переполнены до отрицательного числа. На моей машине это сокращает доступные индексы в два раза! (поскольку оба size_t а также ptrdiff_t 64 бита, но один unsigned а другой signed)

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

  1. В конструкторе примите длину типа ptrdiff_t вместо size_tи добавьте проверку, которая проверяет, что данная длина не является отрицательной.

    Плюсы: Это решает проблему, так как теперь я мог бы получить доступ ко всем элементам в массиве, и все же учесть отрицательные индексы.

    Минусы: Ограничивает максимально возможную длину массива. (например, как я уже говорил ранее, в моей машине он сокращается вдвое)

  2. Оставьте вещи такими, какие они есть, но в [] operatorприведите указатель к типу size_tи использовать тот факт, что отрицательное значение будет переполнено.

    то есть к данному индексу, добавьте разницу между элементом, на который мы сейчас указываем, и

    например, в моем примере раньше, так как vec2 указывает на второй элемент в арее, [] operator будет выглядеть примерно так

    template<class T>
    T& MyVector<T>::operator[] (std::ptrdiff_t index) {
    //Since vec2 points to the second element, we add 1.
    //For vec, we would add 0 since it points at the
    //first element in the array.
    std::size_t actual_index = static_cast<std::size_t>(index + 1);
    
    //Do boundary checking
    
    return this->ptr[actual_index];
    }
    

    Плюсы: Теперь мы можем получить доступ ко всем элементам в массиве.

    Минусы: Использование становится неуклюжим и уродливым.
    Например, если мы создадим вектор размером std::numeric_limits<std::size_t>::max()Затем, чтобы получить доступ к последнему элементу, нам нужно получить доступ к элементу ‘-1’:

    MyVector<int> big_vector(std::numeric_limits<std::size_t>::max());
    big_vector[-1] = 5; // big_vector[-1] is the last element in the array.
    
    MyVector<int> big_vector2 = big_vector + 1;
    std::cout << big_vector2[-2] << std::endl; // would print 5, since big_vector2 points at the second element in the array
    

5

Решение

У меня возникают трудности с выбором между size_t и ptrdiff_t для типа индекса, который должен быть в состоянии хранить отрицательное значение.

Почему вы ограничиваете себя size_t и ptrdiff_t? А как насчет других целочисленных типов?

Есть ли у вас реальный план по внедрению контейнера с элементами 4.294.967.296? (то есть 2 ^ 32).

Я не думаю, что сегодня существует платформа, которая будет выделять столько памяти — по крайней мере, не на компьютерах потребительского уровня. Вы работаете на специализированном оборудовании?

Для универсального C ++ вы можете написать std::size_t — принятие конструктора к std::ptrdiff_t Индексированный класс.

Вам, вероятно, придется настроить допустимый диапазон индексов, так что если вы принимаете отрицательные индексы, эффективный диапазон индексов должен быть (-max32bit, max32bit).

Это означает, что если вы пытаетесь использовать класс с индексом в диапазоне (max32bit, max64bit), ваш класс должен выдать исключение.

Мое решение будет принимать std::size_t в конструкторе (с четкой документацией о том, что индекс варьируется от -max (ptrdiff_t) до макс (ptrdiff_t), а не от 0 до max (std::size_t). Затем класс будет проиндексирован с использованием std::ptrdiff_t,

0

Другие решения


По вопросам рекламы [email protected]