对于具有线性存储的容器,可以使用原始指针代替带有STL算法的迭代器吗?
Can raw pointers be used instead of iterators with STL algorithms for containers with linear storage?
我有一个自定义向量容器,内部存储项目线性数组。昨晚,我试图为我的类实现自定义迭代器,以便能够将它们与STL算法一起使用。我已经取得了一些成功,你可以在这里看到:
自定义迭代器的实例
在这样做的时候,我发现我可以仅仅将原始指针传递给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, 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;
}
没有迭代器的实例
我的问题如下:
- 这是否总是适用于具有线性存储的容器?我知道这不会工作的链接列表,例如。
- 如果它们在这种情况下工作,我为什么要经历实现迭代器的麻烦呢?我知道迭代器是如何泛化我的代码的,但是如果这个简单的数组是我所需要的全部,那么我就没有意义了。
- 如果这种方法总是有效,我正在做的事情的负面问题是什么?首先,我可以看到我正在破坏数据封装。
基于操作符重载的迭代器的一个特点是,指针已经是随机访问的迭代器。在STL的早期,这是一个巨大的设计胜利,因为它使得在现有代码中使用算法变得更容易(同时也使程序员更熟悉接口)。包装一个数组,添加typedef T* iterator; typedef const T* const_iterator
,从begin()
返回&array[0]
,从end()
返回&array[size]
,然后将容器与任何基于迭代器的算法一起使用是完全合理的。正如您已经意识到的,这将适用于任何元素在内存中连续的容器(例如数组)。
你可以实现'real'迭代器,如果:
- 你有一个不同形状的容器(如树或列表);
- 你想在不使迭代器失效的情况下调整数组大小;
- 你想要在你的迭代器使用中添加调试检查,例如检查迭代器是否在失效或容器被删除后被使用,或者绑定检查;
- 你想引入类型安全,并确保人们不会意外地将任意的
T*
分配给my_array::iterator
。
我想说,仅这最后一个优点就值得为其编写一个简单的包装器类。如果你不利用c++的类型系统让不同的东西有不同的类型,你还不如改用Javascript:-)
- 是的。参见Effective STL, Item 16,它演示了使用线性存储容器,您可以简单地获取一个项目的地址并使用该指针,就好像它指向一个简单的数组。
- 我想你已经回答了你自己的问题–如果你知道简单的数组就是你所需要的,那么你可能不应该这样做。
- 可能最大的问题只是& & & ash;破坏数据封装。考虑一下抽象(如显式迭代器类型)与成本相比是否能为您带来任何东西。
对于具有线性存储的容器是否总是有效?
是的,迭代器的概念被设计成指针可以作为数组的迭代器。
在这种情况下,没有理由定义自己的迭代器类型,除非你想做一些像边界检查这样的事情,这是一个简单的指针无法完成的。如果它们在这种情况下确实有效,我为什么还要经历实现迭代器的麻烦呢?
一个小小的好处是,你可以为迭代器的特征包含嵌套类型,就像一些标准迭代器类型所做的那样;但是使用指针,无论如何都可以从std::iterator_traits<T*>
中获得。
如果这种方法总是有效,我正在做的事情的负面问题是什么?首先,我可以看到我正在破坏数据封装。
为了使接口与stl风格的容器更加一致,你应该定义iterator
和const_iterator
类型(指针的typedef
别名),并提供const
对begin
和end
的重载;也许cbegin
和cend
是为了c++ 11的兼容性。
您可能想要遵守各种其他要求;请参阅c++标准的23.2节了解详细信息。但一般来说,使迭代器符合其要求更为重要,因为stl风格的算法与迭代器而不是容器一起工作,并且通过使用指针,您已经符合了这些要求。
指针恰好提供了随机访问迭代器所需的接口(解引用、自增、加法、差值等),并且可以像处理迭代器一样处理。
- 它应该始终适用于具有连续存储的容器。 您可能希望创建自己的迭代器,原因与您在类中使用方法而不是所有公共数据的原因相同:封装可以在需要时修改的接口所发生的事情。只要您将
T*
类型定义为迭代器类型,这可能不是一个重大问题。此外,一些算法可能会从标记了迭代器类型的迭代器中受益,这对于简单的指针类型是无法做到的。- 为什么这个运算符<重载函数对 STL 算法不可见?
- STL算法函数在多个一维容器上的使用
- C++:尝试使用等效的 STL 算法消除原始循环
- STL算法和back_inserter可以预分配空间吗?
- 如何使用 STL 算法将整数向量转换为字符串向量?
- 是否有一种 STL 算法可以最后找到,但它也适用于指针?
- C++ - 如何使用<int> <int>STL 算法功能在矢量<vector>中找到矢量?
- 如何在变量容器上使用stl算法
- 在 stl 算法中移动迭代器
- 如何使用 STL 算法找到最小值和最大值?
- C STL算法相等
- 在 stl 算法中使用函数对象
- 重新定义要在字符串的 STL 算法中使用的<运算符
- 将 STL 算法与 Qt 容器结合使用
- 使用STL算法合并2个向量
- STL算法函数,如累加,如果传递给它们的函数接受引用,请避免复制
- 什么 STL 算法可以确定容器中的一个项目是否满足谓词?
- c ++ 是否有 STL 算法来检查范围是否严格排序
- begin() 和 end() 用于 STL 算法
- STL算法并嵌套以循环