当从 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() - 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())};
}
这让您可以:
for (const auto& s : drop_last(argv)) { ... }
这是高效的(避免了额外的拷贝),避免了未定义的行为(drop_last()
总是给出一个有效范围),而且从名字上就很清楚它的作用。
关于c++ - 使用索引与迭代器将 vector 迭代到倒数第二个元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51217191/