c++ - 使用索引与迭代器将 vector 迭代到倒数第二个元素

标签 c++ c++11 vector iterator std

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

std::vector<const char*> argv;
std::string str;

是否应该使用这种更像 C++ 的方法

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

还是应该首选更传统的方式?

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

最佳答案

请不要这样写:

for (const auto& s: decltype(argv)(argv.begin(), argv.end()-1)) {

首先,当你回顾它时,没有人(包括你)会明白这一点。其次,由于 decltype(argv) 是一个 vector,这是在复制一大堆元素……这仅仅是因为您想避免重复其中的一个吗?那太浪费了。

它还有另一个问题,由您的第二个选项共享。

这个:

for (size_t i = 0; i < argv.size() - 1; ++i) {

的问题要微妙得多,因为 size()unsigned。因此,如果 argv 恰好为空,argv.size() - 1 将是一个非常大的数字,您实际上将访问所有这些无效元素导致未定义行为的数组。

对于迭代器,如果 argv.begin() == argv.end(),那么你不能从 end() 得到前一个迭代器,因为那里 < em>不是 end() 的前一个迭代器。 end() - 1prev(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())};
}

这让您可以:

for (const auto& s : drop_last(argv)) { ... }

这是高效的(避免了额外的拷贝),避免了未定义的行为(drop_last() 总是给出一个有效范围),而且从名字上就很清楚它的作用。

关于c++ - 使用索引与迭代器将 vector 迭代到倒数第二个元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51217191/

相关文章:

c++ - 限定符丢失转换 C++

c++ - c++编译器如何在内存中实现虚拟继承?

c++ - 如何反转可变参数模板函数的参数顺序?

c - 如何在 C 中编写自己的 vector 结构

c++ - 在 C 中使用 char 作为数组索引?

c++ - 查找 vector 中小于阈值(复杂性)的所有数字

c++ - 循环遍历容器作为模板

c++ - 如果语句不起作用,即使语句为真

c++ - 在源文件中定义方法时出错

c++ - 消息映射 MFC : Inheriting multiple message maps