c – 可以使用原始指针,而不是使用具有线性存储容器的STL算法的迭代器?

前端之家收集整理的这篇文章主要介绍了c – 可以使用原始指针,而不是使用具有线性存储容器的STL算法的迭代器?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个自定义向量容器,内部存储项目线性数组.昨天晚上,我试图为我的课程实施自定义迭代器,以便能够使用STL算法.我已经取得了一些成功,你可以在这里看到:

Live example with custom iterators

在这样做的时候,我发现我只能将原始指针传递给STL算法,它们似乎工作正常.以下是没有任何迭代器的示例:

#include <cstddef>
#include <iostream>
#include <iterator>
#include <algorithm>

template<typename T>
class my_array{
    T* data_;
    std::size_t size_;

public:

    my_array()
        : data_(NULL),size_(0)
    {}
    my_array(std::size_t size)
        : data_(new T[size]),size_(size)
    {}
    my_array(const my_array<T>& other){
        size_ = other.size_;
        data_ = new T[size_];
        for (std::size_t i = 0; i<size_; i++)
            data_[i] = other.data_[i];
    }
    my_array(const T* first,const T* last){
        size_ = last - first;
        data_ = new T[size_];

        for (std::size_t i = 0; i<size_; i++)
            data_[i] = first[i];
    }

    ~my_array(){
        delete [] data_;
    }
    const my_array<T>& operator=(const my_array<T>& other){
        size_ = other.size_;
        data_ = new T[size_];
        for (std::size_t i = 0; i<size_; i++)
            data_[i] = other.data_[i];
        return other;
    }
    const T& operator[](std::size_t idx) const {return data_[idx];}
    T& operator[](std::size_t& idx) {return data_[idx];}
    std::size_t size(){return size_;}

    T* begin(){return data_;}
    T* end(){return data_+size_;}
};

template<typename T>
void print(T t) {
    std::cout << t << std::endl;
}

int main(){


    typedef float scalar_t;
    scalar_t list [] = {1,3,5,2,4,10,10};
    my_array<scalar_t> a(list,list+sizeof(list)/sizeof(scalar_t));

    // works!
    for (scalar_t* it = a.begin(),*end = a.end();
         it != end; ++it)
        std::cout << ' ' << *it;
    std::cout << std::endl;

    // works!
    std::for_each(a.begin(),a.end(),print<scalar_t>);
    std::cout << std::endl;

    // works!
    my_array<int> b(a.size());
    std::copy(a.begin(),b.begin());

    // works!
    scalar_t* end = std::remove(a.begin(),5);
    std::for_each(a.begin(),end,print<scalar_t>);
    std::cout << std::endl;

    // works!
    std::random_shuffle(a.begin(),end);
    std::for_each(a.begin(),print<scalar_t>);
    std::cout << std::endl;

    // works!
    std::cout << "Counts of 3 in array = " << std::count(a.begin(),3) << std::endl << std::endl;

    // works!
    std::sort(a.begin(),print<scalar_t>);
    std::cout << std::endl;

    // works!
    if (!std::binary_search(a.begin(),5))
        std::cout << "Removed!" << std::endl;

    return 0;
}

Live example without iterators

我的问题如下:

>这是否适用于具有线性存储容器?我知道这对于链表不起作用.
>如果他们在这种情况下工作,为什么我还要经历执行迭代器的麻烦呢?我知道迭代器如何泛化我的代码,但是,如果这个简单的数组是我需要的,那么我看不到这一点.
>如果这种做法总是有效,我正在做什么的负面问题?一方面,我可以看到我正在打破数据封装.

解决方法

迭代器基于运算符重载的特征之一是指针已经是随机访问迭代器.这是STL早期的一个大设计胜利,因为它更容易使用现有代码的算法(以及使界面更加熟悉程序员).包装数组是非常合理的,添加typedef T * iterator; typedef const T * const_iterator,从你的begin()和& array [size]返回& array [0]从你的end(),然后使用你的容器与任何基于迭代器的算法.您已经意识到,这将适用于内存中元素连续的任何容器(例如数组).

如果有以下情况,您可能会实现“真实”迭代

>您有一个不同形状的容器(如树或列表);
>您希望能够使数组调整大小,而不会使迭代器无效;
>您想要添加调试检查到您的迭代器使用,例如,检查迭代器是否被使用无效之后或容器被删除后,或边界检查;
>你想引入类型安全,并确保人们不能意外地将一个任意的T *分配给my_array :: iterator.

我会说这最后一个优点是值得写一个简单的包装类.如果你不利用C的类型系统,通过使不同种类的东西有不同的类型,你也可以切换到Javascript

猜你在找的C&C++相关文章