copy-and-swap: 拷贝赋值函数的简单实现#
首先明确一点: 如果没有必要定义拷贝构造函数/拷贝赋值函数/析构函数, 就不要定义, 让编译器为你声明甚至定义.
如果有定义的需求, 且拷贝仅仅是拷贝, 不是因为题目而有输出之类的特殊要求, 则可以先定义拷贝构造函数、析构函数, 然后利用它们定义拷贝赋值函数, 这称为 copy-and-swap 惯用法.
拷贝赋值函数#
1Widget& operator=(Widget const& other) {
2 Widget temp(other); // 拷贝 other 到 temp
3 swap(*this, temp); // 交换 temp 和 *this 的内容; 该函数怎么来的见下文
4 return *this;
5} // temp 的析构函数将会对交换来的 *this 内容完成必要的清理
swap
函数#1// 如果是 C++11 及以后, 加上 noexcept 表示不会抛出异常 ↓
2friend void swap(Widget& lhs, Widget& rhs) noexcept {
3 /* 交换 lhs 和 rhs 的所有成员 */
4}
提示
注意到, 这样一来没有必要判断自赋值情况 widget = widget
——自赋值单纯就是得到一份自己的拷贝, 然后与该拷贝发生交换, 最终得到内容仍然是自己.
示例#
1#include <utility> // for std::swap
2
3class Widget {
4 public:
5 Widget(Widget const& other);
6
7 Widget& operator=(Widget const& other) {
8 Widget temp(other); // 拷贝 other 到 temp
9 swap(*this, temp); // 交换 temp 和 *this 的内容
10 return *this;
11 } // temp 的析构函数将会对交换来的 *this 内容完成必要的清理
12
13 ~Widget();
14
15 // 如果是 C++11 及以后, 加上 noexcept 表示不会抛出异常 ↓
16 friend void swap(Widget& lhs, Widget& rhs) /*noexcept*/ {
17 using std::swap; // 先 using std::swap, 再使用不加限定的 swap
18 swap(lhs.array_, rhs.array_);
19 swap(lhs.size_, rhs.size_);
20 }
21
22 private:
23 int* array_;
24 int size_;
25};