Реализация общего массива фиксированного размера с поддержкой итераторов - PullRequest
0 голосов
/ 28 июня 2009

Мне нужен массив, размер которого известен во время компиляции. Я знаю, что могу использовать std :: vector или boost :: array . Но это не учит меня, как это работает внутри. Также я не смог найти, как добавить элементы в boost :: array , кроме как с помощью инициализатора. Я написал следующий код для универсального массива. Я намерен познакомиться с итераторами, специализациями шаблонов и т. Д. Ниже приведен код

template<typename T>
struct iterator_traits
{
    typedef T           value_type;
    typedef T&          reference_type;
    typedef T*          iterator;
    typedef const T*    const_iterator;
    typedef std::reverse_iterator<iterator> reverse_iterator;
};

template<typename T>
struct iterator_traits<T*>
{
    typedef T*          value_type;
    typedef T*&         reference_type;
    typedef T**         iterator;
    typedef const T     const_iterator;
    typedef std::reverse_iterator<iterator> reverse_iterator;
};

template<typename T, size_t size = 10>
class Array
{
    public:

        typedef typename iterator_traits<T>::value_type       value_type;
        typedef typename iterator_traits<T>::reference_type   reference_type;
        typedef typename iterator_traits<T>::iterator         iterator;
        typedef typename iterator_traits<T>::const_iterator   const_iterator;
        typedef typename iterator_traits<T>::reverse_iterator reverse_iterator;

        Array() : lastIndex(0) {
        }

        void add(value_type element) {
            if(lastIndex >= size)
                throw std::out_of_range("Array is full");
            array_[lastIndex++] = element;
        }

        reference_type at(unsigned int index){
            if(index < size)
                return array_[index];
            else
                throw std::out_of_range("Invalid index");
        }

        size_t capacity(){
            return size;
        }

        iterator begin(){
            return array_;
        }

        iterator end(){
            return array_ + size;
        }

        const_iterator begin() const{
            return array_;
        }

        const_iterator end() const{
            return array_ + size;
        }

        reverse_iterator rbegin() {
            return reverse_iterator(end());
        }

        reverse_iterator rend() {
            return reverse_iterator(begin());
        }

    private:

        value_type array_[size];
        unsigned int lastIndex;
};

Код выше работает хорошо. Ниже приведены мои вопросы

1 - Как я могу создать свой массив, как boost :: array ? Что-то вроде

Array<int> ints = { 10, 12 };

2 - Есть ли подводные камни в коде?

3 - Мне пришлось использовать специализацию для типов указателей в чертах. Это лучшая практика?

4 - Шаблон итератора реализован правильно или нет?

Любые мысли были бы великолепны!

Ответы [ 3 ]

2 голосов
/ 28 июня 2009

1 - Как я могу создать свой массив, как Boost :: массив делает? Что-то вроде

Array<int> ints = { 10, 12 };

В c ++ вы можете (в настоящее время) использовать список инициализаторов, заключенный в фигурные скобки, только если ваш массив struct, union или c-style соответствует критерию агрегирования. Для этого, согласно стандарту:

8.5.1.1 Агрегат - это массив или класс (раздел 9) без предоставленных пользователем конструкторов (12.1), без закрытых или защищенных нестатических элементов данных (раздел 11), без базовых классов (раздел 10), и без виртуальных функций (10.3).

Вы должны сделать так, чтобы у вашего класса были эти функции, если вы хотите использовать их в текущем стандарте. Следующий стандарт (см. здесь ) включает положение, позволяющее делать это другим типам.

2 - Есть ли подводные камни в коде?

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

2 голосов
/ 28 июня 2009

boost :: array использует особенность языка: структура без конструкторов может использовать список инициализации. Если вы предоставляете свой собственный конструктор, вы не можете использовать список инициализации.

Кроме того, вы используете iterator_traits неправильно. Ваш код должен быть что-то вроде

    // type definitions
    typedef T              value_type;
    typedef T*             iterator;
    typedef const T*       const_iterator;
    typedef T&             reference;
    typedef const T&       const_reference;
    typedef std::size_t    size_type;
    typedef std::ptrdiff_t difference_type;

iterator_traits для черт итераторов. Также вы можете просто использовать указатель в качестве итератора. STL явно позволяет это.

1 голос
/ 28 июня 2009

2 - есть ли подводные камни?

Я бы избавился от размера по умолчанию "size = 10". Что делает размер по умолчанию для массива 10? Вместо этого я вижу, что кто-то случайно оставляет размер и полагает, что он больше, чем есть.

Что касается добавления элементов и инициализации в стиле C, я не верю, что возможно сделать и то и другое. Он работает в бусте, потому что (я считаю) объект - это просто массив под крышками. Это не может динамически изменить размер. Класс просто добавляет итераторы (и другие сахара, такие как :: at ()) в простой массив.

...