小心,自定義拷貝函式

2022-08-29 08:27:09 字數 2164 閱讀 6237

目錄編譯器在生成拷貝函式時會對所有的類一視同仁,不會特殊情況特殊處理,它只是簡單地將原物件的每乙個non-static資料成員拷貝到目標物件中,這就是所說的淺拷貝。這個過程簡單粗暴,如果類中有動態配置的記憶體,物件中包含資源,問題就會隨之而產生。

首先,我們需要了解一下淺拷貝與深拷貝可能會產生的問題。

淺拷貝是成員資料之間的一一賦值,又稱為bitwise copy。但可能會有這樣的情況:如果物件包含資源(堆資源或檔案),當進行淺拷貝時,兩個資源指標會指向同一資源,就造成兩個物件訪問同一資源的問題,如下所示:

class student ;

student strsrc("xiaohong");

student strdst(strsrc);

寫出上面這樣的**後,會出現如下情況:

淺拷貝的行為類似於memcpy。於是出現了如下問題:在釋放資源的時候會產生資源歸屬不清的情況,這將導致程式執行出錯,這是乙個絕對危險的bug。

深拷貝就是用來解決這個問題的,它會把資源也賦值一次,使物件擁有不同的資源,但其資源的內容是一樣的。以堆資源為例,就是再開闢一片堆記憶體,把原來的內容拷貝過來,如下圖所示:

strdst與strsrc中的指標m_pname不再一樣,它們分別指向了不同的記憶體塊,但是這兩個指標所指向的記憶體塊中的內容卻是一樣的。

自定義拷貝函式是一種良好的程式設計風格,它可以阻止編譯器形成預設的拷貝函式。但是在拒絕編譯器預設版本的同時,你也要注意將拷貝類中所有的資料成員拷貝全了。如果你忘記拷貝某乙個資料成員,你的**並不完善,但編譯器為了「報復」,是不會告訴你相關情況的,它對此依舊會表示同意。假如我們在為student自定義拷貝函式時忽略了資料成員m_nsize,**如下所示:

student::student(const student&rhs)  

student&student::operator=(const student&rhs)

if(m_pname != null)

m_pname = new char[strlen(rhs.m_pname) + 1];

strcpy(m_pname, rhs.m_pname);

return *this;

}

這種實現方式大部分編譯器既不會報錯,也不會通過警告提示你忘記拷貝某個資料成員。這種錯誤一般發生在兩個情形之中:

(1)對原有類進行了新設計,新增了新的資料成員,但是沒有對該類的拷貝函式做適時的更新。

(2)有繼承發生時,忘記對基類部分的資料進行拷貝了。如下所示:

class collegestudent : public student 

collegestudent&operator=(const collegestudent&rhs)

m_nlenofschool = rhs.m_nlenofschool;

return *this;

} ~collegestudent(){}

private:

int m_nlenofschool;

}

上述的拷貝函式貌似對所有資料成員都進行了相應的拷貝,但是它卻忽略了基類部分。派生類的拷貝函式必須呼叫對應的基類函式,所以當你打算自己為乙個派生類自定義拷貝函式時,必須注意同時拷貝其基類部分。上述collegestudent正確的定義方式如下所示:

class collegestudent : public student 

collegestudent&operator=(const collegestudent&rhs)

student::operator=(rhs);

m_nlenofschool = rhs.m_nlenofschool;

return *this;

} ~collegestudent(){}

private:

int m_nlenofschool;

}

所以,如果類中具有動態配置的記憶體,我們需要自行實現拷貝函式。在自定義拷貝函式時,應保證拷貝乙個物件的all parts(所有資料成員、基類部分、指標成員所指向的資源)。

個人主頁:

www.codeapes.cn

自定義拷貝建構函式 預設的拷貝建構函式

自定義拷貝建構函式 類名 類名 const 類名 物件名 拷貝建構函式的函式體 利用下述語句呼叫拷貝建構函式 rectangle p2 p1 include using namespace std class rectangle public rectangle int len,int wid le...

自定義函式 Excel之自定義函式

在excel中,當系統函式不能滿足我們的需求時候,我們可以使用vba自定義函式,如抓取網頁資料,翻譯詞彙,手機號歸屬地查詢等。下面將介紹2個自定義函式,idymd函式 身份證年月日性別 通過身份證號,返回性別,出生年月日。語法 idymd id 引數 id,身份證號,預設身份證長度18位。vba 如...

自定義函式

使用者自定義函式是sqlserver的資料庫物件,他不能應用於一系列改變資料庫狀態的操作。但它可以像系統函式那樣在查詢中或儲存過程中等中的程式段中使用。也可以像儲存過程一樣通過execute命令來執行,使用者自定義函式中儲存了transact sql可以返回一定的值。在sqlserver中根據函式返...