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 閱讀(890)
評論(0) 編輯 收藏 引用