【C++ 实用函数 】C++ 14 std::exchange 使用说明
`std::exchange` 是 C++ 标准库中的一个实用函数,它的主要作用是替换一个对象的值,并返回该对象的旧值。这个函数在 C++14 中引入,主要用于简化和优化代码。
简单介绍
std::exchange
是 C++ 标准库中的一个实用函数,它的主要作用是替换一个对象的值,并返回该对象的旧值。这个函数在 C++14 中引入,主要用于简化和优化代码。
具体来说,std::exchange
的函数原型如下:
template< class T, class U = T >
T exchange( T& obj, U&& new_value );
这个函数接受两个参数:一个是要替换值的对象 obj
,另一个是新的值 new_value
。函数将 obj
的值替换为 new_value
,并返回 obj
的旧值。
std::exchange
的一个常见用途是在实现移动赋值运算符和移动构造函数时使用。例如:
struct S
{
int n;
S(S&& other) noexcept : n{std::exchange(other.n, 0)} {}
S& operator=(S&& other) noexcept
{
if (this != &other)
n = std::exchange(other.n, 0); // move n, while leaving zero in other.n
return *this;
}
};
在这个例子中,移动构造函数和移动赋值运算符使用 std::exchange
将 other.n
的值移动到 n
,并在 other.n
中留下零。这样可以确保 other.n
在移动操作后处于有效状态。
总的来说,std::exchange
是一个非常实用的函数,它可以帮助你在替换对象的值的同时获取其旧值,这在许多情况下都非常有用。
为什么要使用它?
这个函数做的事情是:将obj
的值设置为new_value
,并返回obj
原来的值。
以下是一些std::exchange
的使用场景:
-
在交换操作中:在C++14之前,如果你想交换两个变量的值,你可能需要一个临时变量来保存其中一个变量的值。但是使用
std::exchange
,你可以更简洁地完成这个操作:int a = 5, b = 10; a = std::exchange(b, a);
在这个例子中,
std::exchange
将b
的值设置为a
的值,并将b
原来的值返回给a
,从而实现了a
和b
的交换。 -
在移动语义中:
std::exchange
在处理移动语义时非常有用。例如,你可能想要在类的移动构造函数或移动赋值运算符中使用它:class MyClass { public: // Move constructor MyClass(MyClass&& other) noexcept : ptr_(std::exchange(other.ptr_, nullptr)) {} // Move assignment operator MyClass& operator=(MyClass&& other) noexcept { if (this != &other) { delete ptr_; // delete resource ptr_ = std::exchange(other.ptr_, nullptr); // acquire new resource } return *this; } private: int* ptr_; };
在这个例子中,
std::exchange
用于获取other
的资源(ptr_
),并将other.ptr_
设置为nullptr
,以防止other
在析构时删除资源。 -
在状态转换中:
std::exchange
也可以用于在状态转换中保存旧状态。例如,你可能有一个状态变量,你想要改变它的值,但是你也需要知道它之前的值:enum class State { Idle, Running, Stopped }; State state = State::Idle; // Start running and save the old state State old_state = std::exchange(state, State::Running);
在这个例子中,
std::exchange
将state
的值设置为Running
,并将旧值返回给old_state
。
总的来说,std::exchange
是一个非常实用的工具,它可以帮助你在修改一个对象的值的同时获取其旧值,从而使你的代码更加简洁和清晰。
cppreference网站介绍
定义在头文件 <utility>
中
template< class T, class U = T >
T exchange( T& obj, U&& new_value );
(自 C++14 起)(直到 C++20)
template< class T, class U = T >
constexpr T exchange( T& obj, U&& new_value );
(自 C++20 起)(直到 C++23)
template< class T, class U = T >
constexpr T exchange( T& obj, U&& new_value ) noexcept(/* see below */);
(自 C++23 起)
将 obj 的值替换为 new_value,并返回 obj 的旧值。
参数
- obj:要替换其值的对象
- new_value:要分配给 obj 的值
类型要求
- T 必须满足 MoveConstructible 的要求。此外,必须能够将类型 U 的对象移动分配给类型 T 的对象。
返回值
obj 的旧值。
异常
- (until C++23)
NULL
- (since C++23)
noexcept specification:
noexcept(
std::is_nothrow_move_constructible_v<T> &&
std::is_nothrow_assignable_v<T&, U>
)
可能的实现
template<class T, class U = T>
constexpr // since C++20
T exchange(T& obj, U&& new_value)
noexcept( // since C++23
std::is_nothrow_move_constructible<T>::value &&
std::is_nothrow_assignable<T&, U>::value
)
{
T old_value = std::move(obj);
obj = std::forward<U>(new_value);
return old_value;
}
说明
std::exchange 可用于实现移动赋值运算符和移动构造函数:
struct S
{
int n;
S(S&& other) noexcept : n{std::exchange(other.n, 0)} {}
S& operator=(S&& other) noexcept
{
if (this != &other)
n = std::exchange(other.n, 0); // move n, while leaving zero in other.n
return *this;
}
};
特性测试宏
Feature-test macro | Value | Std | Comment |
---|---|---|---|
__cpp_lib_exchange_function | 201304L | C++14 | std::exchange |
示例
#include <iostream>
#include <iterator>
#include <utility>
#include <vector>
class stream
{
public:
using flags_type = int;
public:
flags_type flags() const { return flags_; }
// Replaces flags_ by newf, and returns the old value.
flags_type flags(flags_type newf) { return std::exchange(flags_, newf); }
private:
flags_type flags_ = 0;
};
void f() { std::cout << "f()"; }
int main()
{
stream s;
std::cout << s.flags() << '\n';
std::cout << s.flags(12) << '\n';
std::cout << s.flags() << "\n\n";
std::vector<int> v;
// 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::exchange(v, {1, 2, 3, 4});
std::copy(begin(v), end(v), std::ostream_iterator<int>(std::cout, ", "));
std::cout << "\n\n";
void (*fun)();
// the default value of template parameter also makes possible to
使用一个普通函数作为第二个参数。下面的表达式等同于 std::exchange(fun, static_cast<void(*)()>(f))
std::exchange(fun, f);
fun();
std::cout << "\n\nFibonacci sequence: ";
for (int a{0}, b{1}; a < 100; a = std::exchange(b, a + b))
std::cout << a << ", ";
std::cout << "...\n";
}
输出:
0
0
12
1, 2, 3, 4,
f()
Fibonacci sequence: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, …
结语
在我们的探索过程中,我们已经深入了解了Shell命令的强大功能和广泛应用。然而,学习这些技术只是开始。真正的力量来自于你如何将它们融入到你的日常工作中,以提高效率和生产力。
心理学告诉我们,学习是一个持续且积极参与的过程。所以,我鼓励你不仅要阅读和理解这些命令,还要动手实践它们。尝试创建自己的命令,逐步掌握Shell编程,使其成为你日常工作的一部分。
同时,请记住分享是学习过程中非常重要的一环。如果你发现本博客对你有帮助,请不吝点赞并留下评论。分享你自己在使用Shell命令时遇到的问题或者有趣的经验,可以帮助更多人从中学习。
此外,我也欢迎你收藏本博客,并随时回来查阅。因为复习和反复实践也是巩固知识、提高技能的关键。
最后,请记住:每个人都可以通过持续学习和实践成为Shell编程专家。我期待看到你在这个旅途中取得更大进步!
阅读我的CSDN主页,解锁更多精彩内容:泡沫的CSDN主页
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)