當心編譯器生成的隱含成員函式 (轉)
“聽說最近新開了家超市?”
“是啊,我去過了,什麼都沒有!”
“真的?什麼都沒有?”
“我騙你幹什麼!只有些牙膏、牙刷、洗衣粉……真的什麼都沒有。”
習以為常的東西總是容易被忽略。在生活中我們可以對這些經常見到的東西視而不見,但在程式碼中千萬不要這樣作。
問題:下面這個類有幾個成員?
class X
{
int value;
};
“這麼簡單的問題還問!我當然知道,會為沒有建構函式的類生成一個預設建構函式,為沒有複製建構函式的類生成一個複製建構函式,為沒有解構函式的類生成一個解構函式,為沒有複製賦值運算子的類生成一個複製賦值運算子,所以它有四個隱含成員函式。”
是的,回答是正確的,但僅限於知道是不行的,必須把它牢牢的記住,直到你一看到這個定義眼前就能浮現出下面的定義:
class X
{
int Value;
public:
X();
X(const X&);
X& operator = (const X&);
~X();
};
為什麼這樣說呢?因為儘管在回答上面的問題時大家都能答對,但在實際應用時卻常常把它忽略掉。讓我們看一個例子:
比如我們要實現一個“智慧指標”(什麼型別的?什麼型別都行,這與本題無關),這,通常都會這樣寫:
template
smart_ptr...
現在我們要為它寫一個複製建構函式和一個複製賦值運算子……等一下。
我們這個智慧指標是為了在某一應用範圍內代替指標的,我們應該讓它支援指標的一些特性,如自動型別轉換的初始化(複製構造)和賦值。而類别範本和真正的指標是不一樣的,即使一個Derived*是一個Base*,但一個smart_ptr
template
smart_ptr
{
T* ptr_data;
public:
T* get_ptr();
template
smart_ptr(const smart_ptr & )
{
ptr_data = Source.get_ptr();
//其它處理
}
template
smart_ptr
{
ptr_data = Source.get_ptr();
//其它處理
}
};
這樣當我們用smart_ptr
當你寫下這樣一段程式碼時:
smart_ptr
...
smart_ptr
smart_ptr
c = a;
你會發現,它並沒有你的建構函式的賦值運算子。什麼原因呢?原因很簡單:當你沒有寫複製建構函式時,編譯器會為你生成一個隱含的複製建構函式。而複製建構函式的定義是“類X的複製建構函式是指第一個引數為const X&、X&、volatile X&或const volatile X&,並且沒有其它引數或其它引數都有預設值的非模板形式的建構函式”,因此上template
template
smart_ptr
{
T* ptr_data;
public:
T* get_ptr();
//以下是編譯器自動生成的三個成員函式
smart_ptr(const smart_ptr
smart_ptr
~smart_ptr();
template
smart_ptr(const smart_ptr & Source)
{
ptr_data = Source.get_ptr();
//其它處理
}
template
smart_ptr
{
ptr_data = Source.get_ptr();
//其它處理
}
};
現在我們看的很清楚了:由於smart_ptr(const smart_ptr
解決辦法很簡單,既然編譯器要呼叫複製建構函式和複製賦值運算子,而隱含的成員又不符合要求,我們就自己寫一個來代替它們:
template
smart_ptr
{
T* ptr_data;
public:
T* get_ptr() const;//返回封裝的指標,可能還需要做一些附加操作,取決於你的智慧指標的設計邏輯。
//自己的複製建構函式和複製賦值運算子:
smart_ptr(const smart_ptr
{
ptr_data = Source.get_ptr();
//其它處理
}
smart_ptr
{
ptr_data = Source.get_ptr();
//其它處理
}
template
smart_ptr(const smart_ptr & Source)
{
ptr_data = Source.get_ptr();
//其它處理
}
template
smart_ptr
{
ptr_data = Source.get_ptr();
//其它處理
}
};
事實上在《C++ STL 中文版》中auto_ptr的實現程式碼中就是這樣實現的。
注:在Nicolai M.Josuttis編寫的《C++ 標準程式庫》(我讀的是侯捷和孟巖的譯本)中把這種建構函式稱為“模板形式的複製建構函式”(原譯文為“template形式的copy建構式”)是一種不很嚴密的說法,容易讓人誤解。事實上這種模板形式的建構函式不屬於複製建構函式。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-997932/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Vue 原始碼解讀(10)—— 編譯器 之 生成渲染函式Vue原始碼編譯函式
- C++特殊成員函式及其生成機制C++函式
- 結構體三種例項化方法(含成員函式)結構體函式
- 引入const成員函式函式
- C++:類的成員函式C++函式
- LLVM編譯器中的內建(built-in)函式LVM編譯UI函式
- 模板函式編譯原理函式編譯原理
- C++ 類成員函式C++函式
- c++ const 成員函式C++函式
- 類內的靜態成員函式函式
- 膨脹的template class成員函式函式
- .Net7 CLR的呼叫函式和編譯函式函式編譯
- 條款06: 若不想使用編譯器自動生成的函式,就該明確拒絕編譯函式
- [譯]隱式轉型,你值得掌握
- 如何使用成員函式指標函式指標
- [譯] 編寫函式式的 JavaScript 實用指南函式JavaScript
- [C++] 成員函式指標和函式指標C++函式指標
- 深入C++成員函式及虛擬函式表C++函式
- 建構函式定義的隱式型別轉換函式型別
- OpenCV(cv::Mat 類的成員函式 ptr<T>())OpenCV函式
- 生成器函式,迭代器函式
- c++智慧指標中的reset成員函式C++指標函式
- C++ 中的 const 物件與 const 成員函式C++物件函式
- 看不懂來打我,vue3如何將template編譯成render函式Vue編譯函式
- 【譯】函式式的React函式React
- 編譯通過的 foo函式返回一個int編譯函式
- C++ 成員資料指標成員函式指標簡單測試C++指標函式
- 嵌入式—編譯器背後的故事編譯
- (譯) 函式式 JS #2: 函式!函式JS
- 類成員函式作為map容器的value使用例項函式
- 繼承關係裡的六個預設成員函式繼承函式
- 類别範本中成員函式建立時機函式
- C++ 成員函式指標簡單測試C++函式指標
- en_concat函式編譯失敗處理函式編譯
- lg生成函式函式
- 序列生成函式函式
- scala簡明教程:偏函式、高階函式、Future非同步程式設計、隱式轉換函式非同步程式設計
- Python利用partial偏函式生成不同的聚合函式Python函式
- C程式碼在編譯的時候,有時候有些函式會被最佳化掉,直接把函式程式碼編譯進呼叫函式里,那在函式宣告前加入“__attribute__((noinline))”C程式編譯函式inline