C++ Weekly - Episode 14 脱水版: Standard Library Gems: next and exchange
这一期主要讲了两个迭代器方法 std::next, std::exchange。
std::next (C++11, C++17)
返回迭代器第 n 个后继节点 (若 n 为负数,则为第 -n 前驱节点)(头文件:#include<iteraotr>)
cppreference: en.cppreference.com/w/cpp/itera…
std::is_sorted 接受迭代器的始末位置并判断是否是排序的. example 1 中 v1 是一个排序的容器,std::is_sorted(v.begin(), v.end()) == true.
对于顺序容器,我们可以通过加法运算来递增迭代器,比如 example 2,也能正确得到 std::is_sorted(v2.begin() + 1, v.end()) == true。
但是加法运算不适用于非顺序容器,如 std::list,见 example 3。 此时将出现编译错误:
error: invalid operands to binary expression ('std::list::iterator' (aka '_List_iterator') and 'int')
为此,可以通过 std::next 进行递推
{
// example 1
std::vector<int> v1 {1, 2, 3, 4, 5, 6, 7};
std::cout << std::is_sorted(v.begin(), v.end()) << std::endl; // true
// example 2
std::vector<int> v2 {3, 2, 3, 4, 5, 6, 7};
std::cout << std::is_sorted(v2.begin() + 1, v.end()) << std::endl; // true
// example 3
std::list<int> v3 {3, 2, 3, 4, 5, 6, 7};
// **error:** **invalid operands to binary expression ('std::list<int>::iterator' (aka '_List_iterator<int>') and 'int')**
// std::cout << std::is_sorted(v3.begin() + 1, v.end()) << std::endl;
std::cout << std::is_sorted(std::next(v3.begin()), v.end()) << std::endl; // true
}
std::exchange (C++14, C++20, C++23)
交换两个值(或对象),并返回老的值.(头文件:#include<utility>),
en.cppreference.com/w/cpp/utili…
该方法使用了移动语义和完美转发,因此能尽可能地避免无谓的拷贝操作,效率比较高。所以入参需要确保是可移动的。C++20 之后,该方法被标记为 constexpr, C++23 之后,该方法进一步标记为 noexcept. [Placeholder]
(作者的用了他的一个软件里面的例子,这里稍微改了下例子说明)
// 假设 obj 是一个对象 (或者容器,函数等), v 是 obj 的容器或者数组
for (int i = 0; i < 1000; ++i) {
calcuate(old); // 假设需要先处理老值,再记住老值,更新新值
old = v[i];
v[i] = v[i + 1];
}
// 使用 std::exchange
for (int i = 0; i < 1000; ++i) {
calcuate(old); // 假设需要先处理老值,再记住老值,更新新值
old = std::exchange(v[i], v[i + 1]);
}
cppreference 提供了更加详细的例子,这里作下部分摘录,一个容器交换,一个是函数交换。
void f() { std::cout << "f()"; }
int main()
{
// Since the second template parameter has a default value, it is possible
// to use a braced-init-list as second argument. The expression below
// is equivalent to std::exchange(v, std::vector<int>{1,2,3,4});
std::vector<int> v;
std::exchange(v, {1,2,3,4});
// the default value of template parameter also makes possible to use a
// normal function as second argument. The expression below is equivalent to
// std::exchange(fun, static_cast<void(*)()>(f))
void (*fun)();
std::exchange(fun,f);
fun();
}