使用迭代器支持实现通用的固定大小数组

[英]Implementing a generic fixed size array with iterator support


I need an array where size is known at compile time. I know I can use std::vector or boost::array. But that's doesn't teach me how it works internally. Also I couldn't find how to add items into boost::array other than using the initializer. I have written the following code for a generic array. My intention is to get familiar with iterators, template specializations etc. Following is the code

我需要一个在编译时已知大小的数组。我知道我可以使用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;
};

The above code works well. Following are my questions

上面的代码效果很好。以下是我的问题

1 - How can I create my array like boost::array does? Something like

1 - 如何像boost :: array一样创建我的数组?就像是

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

2 - Are there any pitfalls in the code?

2 - 代码中是否存在任何缺陷?

3 - I had to use a specialization for pointer types in traits. Is that the best practice?

3 - 我必须对特征中的指针类型使用特化。这是最好的做法吗?

4 - Iterator pattern is implemented correctly or not?

4 - 迭代器模式是否正确实现?

Any thoughts would be great!

任何想法都会很棒!

3 个解决方案

#1


1 - How can I create my array like boost::array does? Something like

1 - 如何像boost :: array一样创建我的数组?就像是

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

In c++, you can only (currently) use a braces enclosed initializer list if your struct, union or c-style array meets the criteria of being an aggregate. To do such, according to the standard:

在c ++中,如果struct,union或c-style数组符合聚合条件,则只能(当前)使用大括号括起初始化列表。要做到这一点,根据标准:

8.5.1.1 An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).

8.5.1.1聚合是一个数组或类(第9条),没有用户提供的构造函数(12.1),没有私有或受保护的非静态数据成员(第11条),没有基类(第10条),没有虚拟功能(10.3)。

You would have to make your class have those features if you wanted to use them in the current standard. The next standard (see here) includes a provision to allow other types to do so.

如果您想在当前标准中使用它们,则必须使您的类具有这些功能。下一个标准(见此处)包括允许其他类型这样做的规定。

2 - Are there any pitfalls in the code?

2 - 代码中是否存在任何缺陷?

Here is one: the reason you can't add things to a boost list is it always has the same number of elements (the size it was allocated with). In your array you can add elements, but you've still constructed 10 elements underneath the hood during construction. this could lead to some suprising results if the user isn't expecting the default constructor called 10 times.

这是一个:你不能将东西添加到提升列表的原因是它总是具有相同数量的元素(分配的大小)。在您的阵列中,您可以添加元素,但在构造期间,您仍然在引擎盖下构建了10个元素。如果用户不期望默认构造函数调用10次,这可能会导致一些令人惊讶的结果。

#2


boost::array uses a feature of the language: A struct with no constructors can use an initialization list. If you provide your own constructor, you can't use an initialization list.

boost :: array使用该语言的一个特性:没有构造函数的struct可以使用初始化列表。如果您提供自己的构造函数,则无法使用初始化列表。

Also, you're using iterator_traits wrong. Your code should be something like

此外,您使用的是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 is for traits of iterators. Also, you can just use a pointer as an iterator. The STL explicitly allows this.

iterator_traits用于迭代器的特征。此外,您可以只使用指针作为迭代器。 STL明确允许这样做。

#3


2 - are there any pitfalls ?

2 - 有任何陷阱吗?

I would get rid of the default size "size = 10". What makes 10 the default size of an array ? What I see happening instead is someone accidentally leaving off the size, and assuming that its bigger than it is.

我会摆脱默认大小“size = 10”。 10是什么使得数组的默认大小?我所看到的恰恰是有人意外地忽略了这个尺寸,并假设它比它大。

Regarding adding elements and the C-style initialization, I don't believe its possible to do both. It works in boost because (I believe) the object is, quite simply, an array under the covers. It can't dynamically re-size. The class simply adds iterators (and other sugar like ::at()) to a plain array.

关于添加元素和C风格的初始化,我不相信它可以做到这两点。它在boost中工作,因为(我相信)该对象非常简单,是一个数组。它无法动态重新调整大小。该类只是将迭代器(和其他糖类如:: at())添加到普通数组中。


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:http://www.silva-art.net/blog/2009/06/27/dcb333df7b454957252bc0af509ee371.html



 
© 2014-2019 ITdaan.com 粤ICP备14056181号