以下面两行代码为例:
for (int i = 0; i < some_vector.size(); i++)
{
//do stuff
}
这:
for (some_iterator = some_vector.begin(); some_iterator != some_vector.end();
some_iterator++)
{
//do stuff
}
有人告诉我第二种方法更可取。为什么会这样呢?
以下面两行代码为例:
for (int i = 0; i < some_vector.size(); i++)
{
//do stuff
}
这:
for (some_iterator = some_vector.begin(); some_iterator != some_vector.end();
some_iterator++)
{
//do stuff
}
有人告诉我第二种方法更可取。为什么会这样呢?
当前回答
这两个实现都是正确的,但我更喜欢'for'循环。由于我们已经决定使用Vector容器而不是其他容器,因此使用索引将是最好的选择。对vector使用迭代器将失去将对象放在连续内存块中的好处,这有助于简化对它们的访问。
其他回答
除了所有其他优秀的答案之外……Int对向量来说可能不够大。相反,如果你想使用索引,使用size_type为你的容器:
for (std::vector<Foo>::size_type i = 0; i < myvector.size(); ++i)
{
Foo& this_foo = myvector[i];
// Do stuff with this_foo
}
比“告诉CPU做什么”(命令式)更好的是“告诉库你想要什么”(函数式)。
因此,你应该学习stl中的算法,而不是使用循环。
我总是使用数组索引,因为我的许多应用程序需要“显示缩略图图像”之类的东西。所以我写了这样的东西:
some_vector[0].left=0;
some_vector[0].top =0;<br>
for (int i = 1; i < some_vector.size(); i++)
{
some_vector[i].left = some_vector[i-1].width + some_vector[i-1].left;
if(i % 6 ==0)
{
some_vector[i].top = some_vector[i].top.height + some_vector[i].top;
some_vector[i].left = 0;
}
}
我觉得这里的答案没有一个能解释为什么我喜欢把迭代器作为一个通用概念,而不是索引到容器中。请注意,我使用迭代器的大部分经验实际上并不是来自c++,而是来自Python等高级编程语言。
迭代器接口对函数的使用者施加的要求更少,这允许使用者使用它做更多的事情。
如果你所需要的只是能够进行前向迭代,那么开发人员就不局限于使用可索引容器——他们可以使用任何实现运算符++(T&)、运算符*(T)和运算符!=(const &T, const &T)。
#include <iostream>
template <class InputIterator>
void printAll(InputIterator& begin, InputIterator& end)
{
for (auto current = begin; current != end; ++current) {
std::cout << *current << "\n";
}
}
// elsewhere...
printAll(myVector.begin(), myVector.end());
你的算法适用于你需要的情况-迭代一个向量-但它也可以用于你不一定预期的应用程序:
#include <random>
class RandomIterator
{
private:
std::mt19937 random;
std::uint_fast32_t current;
std::uint_fast32_t floor;
std::uint_fast32_t ceil;
public:
RandomIterator(
std::uint_fast32_t floor = 0,
std::uint_fast32_t ceil = UINT_FAST32_MAX,
std::uint_fast32_t seed = std::mt19937::default_seed
) :
floor(floor),
ceil(ceil)
{
random.seed(seed);
++(*this);
}
RandomIterator& operator++()
{
current = floor + (random() % (ceil - floor));
}
std::uint_fast32_t operator*() const
{
return current;
}
bool operator!=(const RandomIterator &that) const
{
return current != that.current;
}
};
int main()
{
// roll a 1d6 until we get a 6 and print the results
RandomIterator firstRandom(1, 7, std::random_device()());
RandomIterator secondRandom(6, 7);
printAll(firstRandom, secondRandom);
return 0;
}
试图实现一个方括号操作符来做类似于这个迭代器的事情是不合理的,而迭代器的实现相对简单。方括号操作符还暗示了类的功能——可以将其索引到任意点——实现起来可能比较困难或效率较低。
迭代器也用于修饰。人们可以编写迭代器,在其构造函数中接受迭代器并扩展其功能:
template<class InputIterator, typename T>
class FilterIterator
{
private:
InputIterator internalIterator;
public:
FilterIterator(const InputIterator &iterator):
internalIterator(iterator)
{
}
virtual bool condition(T) = 0;
FilterIterator<InputIterator, T>& operator++()
{
do {
++(internalIterator);
} while (!condition(*internalIterator));
return *this;
}
T operator*()
{
// Needed for the first result
if (!condition(*internalIterator))
++(*this);
return *internalIterator;
}
virtual bool operator!=(const FilterIterator& that) const
{
return internalIterator != that.internalIterator;
}
};
template <class InputIterator>
class EvenIterator : public FilterIterator<InputIterator, std::uint_fast32_t>
{
public:
EvenIterator(const InputIterator &internalIterator) :
FilterIterator<InputIterator, std::uint_fast32_t>(internalIterator)
{
}
bool condition(std::uint_fast32_t n)
{
return !(n % 2);
}
};
int main()
{
// Rolls a d20 until a 20 is rolled and discards odd rolls
EvenIterator<RandomIterator> firstRandom(RandomIterator(1, 21, std::random_device()()));
EvenIterator<RandomIterator> secondRandom(RandomIterator(20, 21));
printAll(firstRandom, secondRandom);
return 0;
}
虽然这些玩具看起来很普通,但不难想象使用迭代器和迭代器装饰器在一个简单的接口上做强大的事情——例如,用一个从单个结果构造模型对象的迭代器装饰数据库结果的仅向前迭代器。这些模式使无限集的内存高效迭代成为可能,并且,使用像我上面写的过滤器,可能会延迟结果的计算。
c++模板的部分强大之处在于你的迭代器接口,当应用于固定长度的C数组时,它会退化为简单高效的指针算术,使其成为真正的零成本抽象。
在对这个问题有了更多的了解之后,我意识到这有点过于简单化了。这个循环的区别是:
for (some_iterator = some_vector.begin(); some_iterator != some_vector.end();
some_iterator++)
{
//do stuff
}
这个循环:
for (int i = 0; i < some_vector.size(); i++)
{
//do stuff
}
相当小。事实上,这样做循环的语法似乎越来越适合我:
while (it != end){
//do stuff
++it;
}
迭代器确实解锁了一些相当强大的声明性特性,当与STL算法库结合使用时,您可以做一些非常酷的事情,这些事情超出了数组索引管理的范围。