C 拷貝建構函式和淺拷貝問題

2021-09-02 00:00:58 字數 3218 閱讀 9970

當使用乙個物件來初始化另乙個同類物件時,編譯器將自動生成乙個建構函式,這個建構函式稱為拷貝建構函式,其格式如下:

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 執...