对于具有线性存储的容器,是否可以使用原始指针而不是STL算法的迭代器? [英] Can raw pointers be used instead of iterators with STL algorithms for containers with linear storage?

查看:90
本文介绍了对于具有线性存储的容器,是否可以使用原始指针而不是STL算法的迭代器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个自定义向量容器,在内部存储项目一个线性数组。昨晚,我试图为我的类实现自定义迭代器,以便能够使用它们与STL算法。我已经取得了一些成功,您可以在这里看到:

I have a custom vector container that internally stores item a linear array. Last night, I was trying to implement custom iterators for my class to be able to use them with STL algorithms. I have had some success that you can see in here:

自定义迭代器的实例< a>

Live example with custom iterators

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

While doing so, I discovered I can merely pass raw pointers to STL algorithm and they just seem to work fine. Here's the example without any iterators:

#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, 3, 5, 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(), a.end(), b.begin());

    // works!
    scalar_t* end = std::remove(a.begin(), a.end(), 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(), end, print<scalar_t>);
    std::cout << std::endl;

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

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

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

    return 0;
}

没有迭代器的实例

我的问题如下:


  1. 这对于具有线性存储的容器总是有效吗?我知道这不会为链接列表工作,例如。

  2. 如果他们在这种情况下工作,为什么我应该经历麻烦实现迭代器呢?我知道迭代器如何推广我的代码和什么,但如果这个简单的数组是所有我需要的,所以我没有看到这一点。

  3. 如果这种方法总是工作,我在做什么的负面问题?一方面,我可以看到我打破了数据封装。


推荐答案

基于运算符重载的迭代器的特征是指针已经是随机访问迭代器。这在STL的早期是一个大的设计胜利,因为它使得更容易使用现有代码的算法(以及使接口更熟悉程序员)。包装数组是非常合理的,添加 typedef T * iterator;从您的 begin()中输入typedef const T * const_iterator ,return & array [0] >和& array [size] ,然后使用您的容器与任何基于迭代器算法。

One of the features of iterators being based on operator-overloading, is that pointers are already random-access iterators. This was a big design win in the early days of STL, as it made it easier to use algorithms with existing code (as well as making the interface more familiar to programmers). It's perfectly reasonable to wrap an array, add typedef T* iterator; typedef const T* const_iterator, return &array[0] from your begin() and &array[size] from your end(), and then use your container with any iterator-based algorithm. As you already realise, this will work for any container where elements are contiguous in memory (such as an array).

你可以实现'real'迭代器if:

You might implement 'real' iterators if:


  • 您有一个不同形状的容器(例如树或列表);

  • 能够调整数组大小而不使迭代器无效;

  • 您希望向迭代器添加调试检查,例如检查迭代器在被无效后或容器已经使用后是否使用已删除或已进行边界检查;

  • 您要引入类型安全性,并确保用户不会意外分配任意 T * my_array :: iterator

  • You have a different-shaped container (such as a tree or list);
  • You want to be able to resize the array without invalidating the iterators;
  • You want to add debugging checks to your iterator use, for example to check if the iterator is used after being invalidated or after the container has been deleted, or to bounds-check;
  • You want to introduce type-safety, and make sure people can't accidentally assign an arbitrary T* to a my_array::iterator.

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

I'd say this last advantage alone is well worth writing a trivial wrapper class for. If you don't take advantage of C++'s type system by making different kinds of thing have different types, you might as well switch to Javascript :-)

这篇关于对于具有线性存储的容器,是否可以使用原始指针而不是STL算法的迭代器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆