作者 ie945167 (龍蝦) 站內 Lobster
標題 [筆記] 複製建構式 copy-constructor
時間 2012/04/04 Wed 17:31:47
───────────────────────────────────────
不負責任聲明:以下憑印象+google寫成,有錯誤很正常 0rz
如果有人願意指出錯誤,我會很感謝您的 <(_ _)>
--------------------本文開始分隔線--------------------
複製建構式:
A::A(const A &a )
{
}
前一篇文章有提到,C++標準中有幾個函式你不需要寫,C++都會幫你生出來,
而你寫了,就不會幫你產生,複製建構式是其中一個
那什麼時候會需要自己寫一個?
Ans:當有使用指標的時候,不然 copy 的會是 pointer,而不是 data
1. http://www.cnblogs.com/oomusou/archive/2007/01/14/620374.html
當類別資料copy涉及記憶體時,永遠要寫複製建構式與operator =();
複製建構式: A::A(const A &a ){}
指定運算元: A::operator =( const A& a ){}
不然在解構時,同一個運算元會被解構兩次而造成 code 掛掉
2. http://imandrewliao.blogspot.com/2009/01/blog-post_22.html
(第三點的內容)
另外印象中好像有提到在使用 copy-constructor 時
會配合使用 swap function 來做資料的交換
(不過我不知道原因為何…0rz)
如交換 a, b 資料 → a.swap(b)
temp(b)
this → swap(b)
return *this;
另外
(a = b).function;
與
a = b;
a.function
是相同的
--------------------------------------------------
以下是第一個連結的全文轉貼,避免連結失效
(原創) 哪些地方會用到Copy Constructor和Assignment Operator? (C/C++)
C#、Java都沒有copy constructor,所以這對大部分programmer都很陌生
簡單地說,凡需要copy的地方,就需要copy constructor:
1.由copy-initialization方式建立物件。
Ex.
Foo foo1;
Foo foo2(foo1);
以上直接使用copy constructor。
string s = "C++ Primer";
Foo foo = Foo();
此時是先由default constructor建立一個temporary object後,
再由copy constructor將temporary object 『copy』給物件。
2.以by value的方式傳進function和由function return值。
Ex.
int Foo(int n);
只要不是使用by reference的方式,就得使用copy constructor。
3.建立STL container中的element。
Ex.vector<string> svec(5);
先由string的default constructor建立一個temporary string object,
再由string的copy constructor『copy』到vector中每個element。
4.由initialization list建立array。
Ex.int ia[] = {1, 2, 3};
先由int default contructor先建立temporary int object,
再由int的copy contructor『copy』到array中。
所以copy constructor其實是無所不在的,只是我們從來沒有發現,
雖然C++ compiler會自己synthesize copy constructor,
但也允許我們自己定義自己的Copy Constructor,這與C#、Java不同。
而assignment operator呢?
Foo foo1;
Foo foo2;
foo2 = foo1;
以上會執行foo2的assignment operator。
所以簡單的說,copy constructor和assignment operator都在做『copy』的動作,
資料是pointer,也就是動態資料時,就必須重新改寫,
否則只會copy pointer,而不是copy data。
--------------------------------------------------
以下是第二個連結的全文轉貼,避免連結失效
建構式與解構式
預設建構式與解構式有許多的地雷,首先,如先前所說,
C++在你沒有撰寫此兩個函式的時候,會自動生成,
那麼因為建構式支援多載,預設解構式還會生成嗎?
答案是不會的,以下以範例說明:
class ClassHasDefaultConstruct
{
};
class ClassHasNoDefaultConstruct
{
public:
ClassHasNoDefaultConstruct(int i){}
};
我們可以注意到第二個範例,有寫建構式但不是預設建構式(沒有任何參數的),
此時C++就放棄幫你建立預設建構式了,
可是有時候,我們在使用STL函式庫的時候,強迫要求你設計預設建構式,
所以ClassHasNoDefaultConstruct這個類別是不能為STL容器所用。
這裡有個小伎倆,把有參數的建構式當成預設建構式用,利用預設參數的方式:
class ClassHasNoDefaultConstruct2
{
public:
ClassHasNoDefaultConstruct2(int i=0){}
};
使用建構式有一些注意事項,如果你的類別支援繼承,在建構式中,不可呼叫虛擬函式,
因為,物件建構的順序是:基底類別建構式完成後,然後才是衍生類別建構,
所以在基底類別建構式中呼叫虛擬函式,永遠是基底類別的函式
其次養成習慣,最好在建構式中,給予所有變數初值,避免執行期間產生錯誤,
因為一般而言,
C++在除錯版的時候,會自動給定變數初值(0, NULL),
而Release版不會,
變數值是看當時配置的記憶體資料內容而定,
所以典型的程式描述是我Debug版跑起來都沒錯,但是Release版就是會當機...。
class BadSample
{
private:
char *ptr;
public:
BadSample(){};
~BadSample()
{
if( ptr ) delete ptr; // 當機
};
};
第三是當類別資料copy涉及記憶體時,永遠要寫複製建構式與operator =();
或者,類別不允許這兩個函式的執行,
原因很簡單,以下以程式說明之:
class CopyConstructor
{
private:
char *ptr;
public:
void ANewFunction()
{
ptr=new char[1024];
}
~CopyConstructor()
{
if( ptr ) delete[] ptr; // 假設建構式有把ptr=NULL;
}
};
以下例子解構時都會當機,因為ptr會被釋放多次:
CopyConstructor a;
a.ANewFunction();
CopyConstructor b(a); // b物件刪除的時候,ptr釋放一次,等到a物件刪除時,又一次
CopyConstructor c;
c=a; // 同上
所以要嗎你把類別這麼寫:
class CopyConstructor
{
private:
char *ptr;
public:
void ANewFunction()
{
ptr=new char[1024];
}
CopyConstructor(const CopyConstructor& c )
{
ptr=new char[1024]; // 各自配置各自的記憶體
memcpy( ptr, c.ptr, 1024 );
}
void operator =(const CopyConstructor& c ) // 簡化起見,不討論回傳值
{
ptr=new char[1024]; // 各自配置各自的記憶體
memcpy( ptr, c.ptr, 1024 );
}
~CopyConstructor()
{
if( ptr ) delete[] ptr; // 假設建構式有把ptr=NULL;
}
};
要嗎你把類別這麼寫:
class CopyConstructor
{
private:
char *ptr;
public:
void ANewFunction()
{
ptr=new char[1024];
}
CopyConstructor(const CopyConstructor& c )
{
ASSERT(0); //給他當機
}
void operator =(const CopyConstructor& c ) // 簡化起見,不討論回傳值
{
ASSERT(0); //給他當機
}
~CopyConstructor()
{
if( ptr ) delete[] ptr; // 假設建構式有把ptr=NULL;
}
};
解構式的注意事項是,如果想讓後續類別繼承,
一定要用virtual,讓繼承解構的順序正確,
還有,同建構式般,不可以在解構式中,呼叫虛擬函式,
因為解構是繼承物件先解構,然後才基底物件,
衍生物件已經不見了,基底物件去哪呼叫正確的虛擬函式呢?
--
身高不是距離
技巧不是問題
只要有"心"
人人都可 定‧三‧米
--
▅◣ Origin: 謠 言 報 bbs.csie.fju.edu.tw
▋◤ Author: ie945167 從 219-85-0-189-adsl-nei3.dynamic.so-net.net.tw 發表
▋※ Modify: 2012/04/04 Wed 17:39:15