swap 到底做了什么
swap 交换两个内置数据类型的变量时,直接交换。
swap 交换自定义类型对象时,如果里面没有成员指针,直接交换各个对应成员。
如果自定义类型中有指针成员,则是交换两个指针的值,但是指针的指向的值得不到交换。
正是由于这个原因,可以用 swap 进行重载 operator = 时避免自赋值情况,而是生产一个临时对象,然后与本对象 swap 即可。
关于重载 operator = 自赋值的情况,更详细内容可以查看《Effective C++》
实验程序:
1 #include <iostream>
2 using namespace std;
3
4 class Str
5 {
6 private:
7 char* s_;
8 public:
9 Str(const char* s = "")
10 {
11 s_ = new char[strlen(s) + 1];
12 if (s_ == 0)
13 {
14 cout << "test" << endl;
15 exit(1);
16 }
17 strcpy(s_, s);
18 }
19 // 定义拷贝构造函数,这里会被用于 operator =,swap
20 Str(const Str& rhs)
21 {
22 s_ = new char[strlen(rhs.s_) + 1];
23 if (s_ == 0)
24 {
25 cout << "test" << endl;
26 exit(1);
27 }
28 strcpy(s_, rhs.s_);
29 }
30 ~Str()
31 {
32 clear();
33 }
34 //// 常规的 operator = 重载实现方式,必须检查自赋值
35 //// 因为如果不自赋值检验,对于自赋值现象如果不调用 clear,则 s_ 在 new 之后就改变,rhs 也改变,原来的丢失,后来的也不是合法内容
36 //// 如果调用 clear,不会内存泄露,但是 rhs 的内容被释放掉,rhs 的内容也不是合法内容。
37 //// 如果检验自赋值,而没有 clear,原来 *this 的那块内存会被丢失,造成内存泄露。
38 //Str& operator = (const Str& rhs)
39 //{
40 // if (this != &rhs)
41 // {
42 // clear();
43 // s_ = new char[strlen(rhs.s_) + 1];
44 // if (s_ == 0)
45 // {
46 // exit(1);
47 // }
48 // strcpy(s_, rhs.s_);
49 // }
50 // return *this;
51 //}
52
53 // 改进的 operator,先用一个 temp 保持 rhs,然后 swap
54 // 这种方式不怕自赋值,因为如果是自赋值,也有一个备份 temp,操作值相同的两个对象 *this 和 temp,直接交换不会影响结果
55 // 如果不是自赋值,不是交换 *this 和 rhs,而是交换 *this 和 rhs 的一个复制品 temp,最终 *this 得到的值就是 rhs 的一个副本,完成赋值
56 // 这种方式不用检验自赋值,所以可以省去每次调用时的自赋值检验,在基本上不会遇到自赋值检验的情况下,这种方法可以省去很多误用的检验
57 // 但是它会每次生成一个副本,这样做的效率与原来的非自赋值一样,而且还需要一个 swap,但是这种方式是异常安全的,用对象来管理资源,资源分配即初始化
58 Str& operator = (const Str& rhs)
59 {
60 cout << "test" << endl;
61 Str temp(rhs);
62 // swap(*this, temp);
63 // 这里会引起递归调用,因为 operator = 调用 swap,swap 内部又调用 operator = ,一直递归下去,直到栈溢出
64 swap(s_, temp.s_);
65 // Effective C++ 中提到,可以定义一个成员函数 swap,用于交换两个对象对应的数据成员。这样可以防止无限递归。
66 // 另一种好的方式是除定义一个成员函数 swap 外,传参类型为 值类型 T,这样就可以直接交换返回。
67 // 这些方法的前提都是要有定义拷贝构造函数的。
68 return *this;
69 }
70
71 void clear()
72 {
73 delete [] s_;
74 }
75 void foo()
76 {
77 cout << s_ << endl;
78 }
79 };
80
81 int main()
82 {
83 int a = 3, b = 5;
84 swap(a, b);
85 cout << a << endl;
86 cout << b << endl;
87
88 Str s1("abc");
89 Str s2("xyz");
90 s1.foo();
91 s2.foo();
92
93 swap(s1, s2);
94 // 这里输出两个 test,我们得知,有两个赋值操作
95 // 可以推测 swap 的内部实现是 T t(s2), s2 = s1, s1 = t;
96 s1.foo();
97 s2.foo();
98
99 s2 = s1;
100 s1.foo();
101 s2.foo();
102
103 return 0;
104 }
posted on 2011-05-27 22:14
unixfy 阅读(869)
评论(0) 编辑 收藏 引用