一般來說,如果乙個類中有指標成員,則要小心拷貝成員函式的編寫,因為如果不注意,則會造成程式的記憶體洩漏。如下所示的例子。
#include
class hasptrmem
~hasptrmem()
}int *m_data;
};int main()
我們申明了乙個帶有指標成員的hasptrmem類,在main函式中宣告了物件a,再用物件a去初始化b,由於類中沒有顯示宣告拷貝建構函式,則按照c++語法會呼叫編譯器隱式生成的拷貝建構函式。這樣就會出現以下乙個問題:
a和b的m_data和都指向同一塊堆記憶體,因此在main作用域結束後,a和b的析構函式依次被呼叫,比如b.m_data所指向的記憶體先被釋放後,a.m_data就無法再對其進行操作,從而導致記憶體洩漏。上述拷貝構造方式就是淺拷貝(shallow copy):只對資料成員進行簡單的賦值。
深拷貝(deep copy):針對存在指標資料成員的情況下,重新分配記憶體空間,不再是簡單的指標賦值。如下所示。
#include
class hasptrmem
hasptrmem(hasptrmem& h) : m_data(new
int(*h.m_data)){} //拷貝建構函式,從堆中分配記憶體,用h.m_data初始化
~hasptrmem()
}int *m_data;
};int main() //正常析構
執行結果: 0 0
上述結果就不會報錯,新的拷貝建構函式從堆中分配心記憶體,將分配來的記憶體的指標交給m._data,通過這樣的方法,就能避免產生懸掛指標(dangling pointer)。
如果指標所指向非常大的記憶體資料的話,則拷貝構造的代價就非常昂貴,會極大地影響效能。c++11提供一種簡潔解決方法:移動建構函式,即是在用原物件指針對新物件指標進行賦值後,將原物件成員指標置為空指標,使得其無法指向記憶體資料,從而保證在析構的時候不會產生記憶體洩漏。這樣既不用分配新記憶體,也不會產生記憶體洩漏,從而很好地解決了上述問題。如下所示。
#include
class hasptrmem
hasptrmem(const hasptrmem &h) : m_data(new
int(*h.m_data))
hasptrmem(hasptrmem&& h) :m_data(h.m_data)
~hasptrmem()
std::cout
<< "destruct: "
<< ++n_dstr << std::endl;
}int *m_data;
static
int n_cstr;
static
int n_dstr;
static
int n_cptr;
static
int n_mvtr;
};int hasptrmem::n_cstr = 0;
int hasptrmem::n_cptr = 0;
int hasptrmem::n_mvtr = 0;
int hasptrmem::n_dstr = 0;
hasptrmem gettemp()
int main()
執行結果:
construct: 1
resource from gettemp:000000e2e9b55d00
move construct: 1
destruct: 1
resource from main:000000e2e9b55d00
destruct: 2
gettemp()函式返回了h的乙個臨時變數時,呼叫了移動建構函式,其中的h和main中的a的指標成員值是相同的,說明了h.m _data和a.m _data都指向了相同的堆記憶體位址.因此其指標在gettemp函式返回時免於被析構的「命運」,成為main中a的變數。
移動建構函式能解決佔記憶體較大的物件的拷貝構造問題,對提高系統效能有很好的作用。
C 11新特性 移動建構函式和移動賦值
移動建構函式就是從拷貝建構函式演化而來的。拷貝建構函式又分為淺拷貝和深拷貝 因此就產生了移動建構函式,將原來物件的東西移動到新的物件上 移動後當物件銷毀時不能發生錯誤 移動後原物件不再指向被移動的資源,這些資源的所有權已經歸屬新建立的物件 a a x a a x 上面兩種就是拷貝建構函式和移動建構函...
C 11新特性學習
lambda表示式用於建立匿名的函式物件,語法為 函式可訪問的的外部變數 函式引數 返回值型別 如 int a 1,b 2 int c b int x int b 表示函式中可以訪問外部變數b,而且引數b是按值傳遞,b 表示引數b是按引用傳遞,表示可以訪問所有外部變數,並且是用按值傳遞方式,類似,也...
C 11新特性學習筆記(二)
c 11引入了lambda 匿名函式 這樣就可以在乙個函式只需呼叫一次的地方使用了,類似內聯函式。c 11 的 lambda 表示式規範如下 capture params mutable exception attribute ret 1 capture params ret 2 capture p...