(原創) 為什麼C++須重新定義Copy Control? (C/C++)
C#、Java都沒有Copy Control,為什麼C++需要有Copy Control呢?
C++是個Hybrid語言,除了built-in type和Class type外,還有個其他語言都沒有的歷史產物:pointer,pointer的用途很多,其中一個用途是因為Dynamic Allocation,而且這種由Dynamic Allocation產生的pointer有幾個特點,第一就是他存的是Memory Address不是Data,所以Copy Constructor和Assignment Operator會有問題,第二就是須delete才會消失,不會隨著object out of scope而消失,有static的味道,所以必須自己在Destructor處理。C#、Java因為沒有pointer,因此不需手動處理Copy Constructor和Assignment Operator,但C#、Java雖有Garbage Collection,但C#仍有Destructor,主要是為了處理非Managed的Resource,如File Handler,Database Connection,但Java已經沒有Destructor了。
回到主題,C++的Copy Contructor和Assignment Operator有什麼問題呢?由Compiler所synthesized的程式,只會將pointer加以複製,很顯然最後指向的結果仍是同一份,這樣就沒有達到Copy的意義了,所以我們得自己重新定義Copy Constructor和Assignment Operator。至於Destructor,因為須手動delete,所以Destructor也必須重新定義。換言之,只要Data Member有用到pointer,也就是動態資料結構時,Copy Constructor、Assignment Operator、Destructor就必須重新定義。
以下範例Demo如何撰寫Copy Control處理單一動態資料和動態陣列。
2 (C) OOMusou 2007 http://oomusou.cnblogs.com
3
4 Filename : CopyControl.cpp
5 Compiler : Visual C++ 8.0 / ISO C++
6 Description : Demo how to use Copy Control with dynamic allocation
7 Release : 01/15/2007 1.0
8 */
9#include <iostream>
10
11using namespace std;
12
13class Foo {
14// Constructor
15public:
16 Foo(int n = 0) : i(n), pi(new int(n)), pia(new int[n]) { cout << "Constructor" << endl; }
17
18public:
19 // Copy Constructor
20 Foo (const Foo&);
21 // Assignment Operator
22 Foo& operator=(const Foo&);
23 // Destructor
24 ~Foo();
25
26public:
27 int getStaticInt();
28 int getDynamicInt();
29 int getDynamicArray(int);
30 void setDynamicArray(int, int);
31
32private:
33 int i; // static int
34 int *pi; // dynamic int
35 int *pia; // dynamic int array
36};
37
38// Synthesized Copy Constructor
39/*
40Foo::Foo(const Foo& foo) {
41 this->i = foo.i;
42 this->pi = foo.pi; // Error!! just copy pointer
43 this->pia = foo.pia; // Error!! just copy pointer
44}
45*/
46
47// Correct Copy Constructor
48Foo::Foo (const Foo& foo) {
49 this->i = foo.i;
50
51 this->pi = new int(*foo.pi);
52
53 this->pia = new int[foo.i];
54 for(int n = 0; n != this->i; ++n)
55 this->pia[n] = foo.pia[n];
56
57 cout << "Copy Constructor" << endl;
58}
59
60// Synthesized Assignment Operator
61/*
62Foo& Foo::operator=(const Foo& foo) {
63 this->pstring = foo.pstring; // error!! just copy pointer
64 this->i = 0;
65 this->d = 0.0;
66 return *this;
67}
68*/
69
70// Correct Assignment Operator
71Foo& Foo::operator=(const Foo& foo) {
72 this->i = foo.i;
73
74 *this->pi = *foo.pi;
75
76 /*while(this->pia < this->pia + foo.i)
77 *(this->pia++) = *(foo.pia++);*/
78
79 for(int n = 0; n != this->i; ++n)
80 this->pia[n] = foo.pia[n];
81
82 cout << "Assign Operator" << endl;
83
84 return *this;
85}
86
87// Destructor
88Foo::~Foo() {
89 // delete dynamic int
90 delete this->pi;
91 // delete dynamic int array
92 delete [] this->pia;
93
94 cout << "Destructor" << endl;
95}
96
97int Foo::getStaticInt() {
98 return this->i;
99}
100
101int Foo::getDynamicInt() {
102 return *this->pi;
103}
104
105int Foo::getDynamicArray(int n) {
106 return this->pia[n];
107}
108
109void Foo::setDynamicArray(int n, int val) {
110 if (n >= 0 && n < this->i)
111 this->pia[n] = val;
112}
113
114int main() {
115 Foo foo1;
116 cout << foo1.getStaticInt() << endl;
117 cout << foo1.getDynamicInt() << endl;
118
119 Foo foo2(3);
120 cout << foo2.getStaticInt() << endl;
121 cout << foo2.getDynamicInt() << endl;
122
123 for(int n = 0; n != 3; ++n)
124 foo2.setDynamicArray(n, n+1);
125
126 cout << foo2.getDynamicArray(0) << endl;
127
128 Foo foo3(foo2); // foo3's Copy Constructor
129 Foo foo4 = foo2; // Syntax sugar!! foo4's Copy Constructor
130
131 Foo foo5(3);
132 foo5 = foo3; // foo5's Assignment Operator
133 cout << foo5.getDynamicArray(1) << endl;
134}
執行結果
0
0
Constructor
3
3
1
Copy Constructor
Copy Constructor
Constructor
Assign Operator
2
Destructor
Destructor
Destructor
Destructor
Destructor