當使用乙個物件來初始化另乙個同類物件時,編譯器將自動生成乙個建構函式,這個建構函式稱為拷貝建構函式,其格式如下:
customclass(const customclass & obj);
在之前說過,建立類時,如果沒有提供建構函式,那麼編譯器將會自動提供乙個預設的建構函式。
拷貝建構函式也是一樣,如果沒有提供拷貝建構函式,那麼編譯器將會提供乙個預設的拷貝建構函式。
當程式中使用乙個物件初始化乙個新物件時,都會呼叫拷貝建構函式,這種情況包括以下兩類:
這種情況非常明顯,如:
mystring str1
("hello world.");
mystring str2 = str1;
mystring str3 =
mystring
(str1)
;mystring str4
(str1)
;mystring *p_str =
newmystring
(str1)
;//p_str指向乙個匿名mystring物件
因此,函式中經常使用引用傳遞,避免空間和時間的浪費。預設的拷貝建構函式逐個複製非靜態成員,複製的是成員的值,稱為淺拷貝。因此,如果成員為指標變數時,則容易引發問題,通過如下示例來說明。
這裡我們定義乙個student類,如下:
student.h:
#include
class
student
;
student.cpp:
#include
#include
"student.h"
int student::number =0;
student::
student()
student::
student
(int age,
const
char
* arr)
student::
~student()
std::ostream &
operator
<<
(std::ostream & os,
const student & stu)
mainstu.cpp:
#include
#include
"student.h"
intmain()
這裡利用stu2物件來初始化stu3,在執行時,發生錯誤:
@ubuntu:$ g++ student.h student.cpp mainstu.cpp -o mainstu
@ubuntu:$ ./mainstu
none created by stduent(
)xiaoming created by student(int,char *)
xiaoming deleted by ~student(
)1 left.
deleted by ~student(
)0 left.
*** error in `./mainstu': double free or corruption (fasttop): 0x00000000010f9050 ***
為何會出現double free or corruption
呢?
由於拷貝構造只是複製成員的值,因此該例中stu2.name和stu3.name就指向同一塊記憶體,當程式結束呼叫後,析構stu2和stu3時,由於指向同一塊記憶體,導致該區域記憶體被析構兩次。
除以上這種情況外,如下的方法呼叫也會導致同樣問題:
void
showstu
(const student stu)
由於函式按值傳遞時,也會呼叫拷貝建構函式,僅僅將實參的值拷貝給了形參,從而導致同乙個記憶體被析構兩次。
要解決由拷貝構造引起的淺拷貝問題,就必須顯式實現拷貝建構函式,而不是使用由編譯器提供的預設拷貝構造了。
student::
student
(const student & stu)
在拷貝建構函式中,根據實參中陣列的大小,重新動態申請了一塊記憶體,從而避免兩個物件共用同乙個記憶體。
再次編譯並執行程式,程式完整輸出:
@ubuntu:$ g++ student.h student.cpp mainstu.cpp -o mainstu
@ubuntu:$ ./mainstu
none created by stduent(
)xiaoming created by student(int,char *)
xiaoming
xiaoming deleted by ~student(
)2 left.
xiaoming deleted by ~student(
)1 left.
none deleted by ~student(
)0 left.
除了拷貝建構函式外,賦值運算子=
也會引起淺拷貝問題,如:
int
main()
預設情況下,複製運算子也是對成員的值進行複製,因此也將導致指標型別的成員變數指向同乙個位址,從而引起錯誤。
所以,通過過載=
運算子來解決這個問題,過載方式和拷貝建構函式類似,但有點差別:
過載邏輯如下:
student & student::
operator=(
const student & stu)
凡是使用到new的類通常都需要提供拷貝建構函式和過載賦值運算子,以防止淺拷貝引起的問題。
如果希望這個類不使用拷貝構造和賦值運算子,可以將它們在類宣告時定義為private
形式,如:
class
student
; student &
operator=(
const student & stu);}
;
C 拷貝建構函式 淺拷貝和深拷貝
建構函式可以沒有,也可以有多個。複製建構函式只有乙個,不定義編譯器自動生成,使用者寫就使用自定義的複製建構函式 物件之間的複製語句不會呼叫複製建構函式。利用編譯器提供的拷貝建構函式,會做淺拷貝 淺拷貝帶來的問題就死堆區記憶體的重複釋放 案例1 class student student 程式正常輸出...
C 拷貝建構函式 深拷貝,淺拷貝
對於普通型別的物件來說,它們之間的複製是很簡單的,例如 int a 88 int b a 而類物件與普通物件不同,類物件內部結構一般較為複雜,存在各種成員變數。下面看乙個類物件拷貝的簡單例子。執行程式,螢幕輸出100。從以上 的執行結果可以看出,系統為物件b分配了記憶體並完成了與物件a的複製過程。就...
C 拷貝建構函式 深拷貝,淺拷貝
對於普通型別的物件來說,它們之間的複製是很簡單的,例如 int a 88 int b a 而類物件與普通物件不同,類物件內部結構一般較為複雜,存在各種成員變數。下面看乙個類物件拷貝的簡單例子。include using namespace std class cexample void show 執...