使用索引与迭代器迭代向量到倒数第二个元素

che*_*cks 9 c++ iterator vector std c++11

当从C++ 11的开头迭代std::vector到第二个到最后一个元素时,首选的样式是什么?

std::vector<const char*> argv;
std::string str;
Run Code Online (Sandbox Code Playgroud)

应该使用这种更多的C++ - esque方法

for (const auto& s: decltype(argv)(argv.begin(), argv.end()-1)) {
    str += std::string(s) + ' ';
}
Run Code Online (Sandbox Code Playgroud)

还是应该采用更传统的方式?

for (size_t i = 0; i < argv.size() - 1; ++i) {
    str += std::string(argv[i]);
}
Run Code Online (Sandbox Code Playgroud)

Bar*_*rry 12

请不要这样写:

for (const auto& s: decltype(argv)(argv.begin(), argv.end()-1)) {
Run Code Online (Sandbox Code Playgroud)

首先,当你回顾它时,没有人(包括你)会理解这一点.其次,既然decltype(argv)是a vector,这就是复制了一大堆元素......只是因为你想避免迭代其中一个元素?那太浪费了.

它还有另一个问题,您的第二个选项会共享该问题.

这个:

for (size_t i = 0; i < argv.size() - 1; ++i) {
Run Code Online (Sandbox Code Playgroud)

因为size()无符号的,所以更微妙的问题.因此,如果argv恰好是空的,argv.size() - 1将会是一些非常大的数字,并且您实际上将访问数组的所有这些无效元素,从而导致未定义的行为.

对于迭代器,如果argv.begin() == argv.end(),则无法从获得以前的迭代end(),因为从没有先前的迭代器end().所有的end() - 1,prev(end())--end()未定义行为.那时,我们甚至无法推断循环会做什么,因为我们甚至没有有效的范围.


我建议的是:

template <typename It>
struct iterator_pair {
    It b, e;

    It begin() const { return b; }
    It end() const { return e; }
};

// this doesn't work for types like raw arrays, I leave that as
// an exercise to the reader
template <typename Range>
auto drop_last(Range& r) 
    -> iterator_pair<decltype(r.begin())>
{
    return {r.begin(), r.begin() == r.end() ? r.end() : std::prev(r.end())};
}
Run Code Online (Sandbox Code Playgroud)

这可以让你做到:

for (const auto& s : drop_last(argv)) { ... }
Run Code Online (Sandbox Code Playgroud)

这是有效的(避免额外的副本),避免未定义的行为(drop_last()总是给出一个有效的范围),并且很清楚它从名称中做了什么.


lub*_*bgr 6

我发现第一个选项有点笨拙,但是因为这是个人偏好的问题,我提出了一种避免手写循环的备选方法(并且在假设的情况下argv.size() >= 1),这在某种意义上可能更好减少错别字和索引错误的可能性.

#include <numeric>

std::string str;

if (!argv.empty())
    str = std::accumulate(argv.begin(), std::prev(argv.end()), str);
Run Code Online (Sandbox Code Playgroud)

  • 很好用`accumulate`. (2认同)
  • `--argv.end()`不保证有效.另一方面,`argv.end() - 1`是. (2认同)
  • @chewsocks对吗?指针仍然是迭代器. (2认同)