先考慮一種情況,對一個(gè)已知對象進(jìn)行拷貝,編譯系統(tǒng)會(huì)自動(dòng)調(diào)用一種構(gòu)造函數(shù)——拷貝構(gòu)造函數(shù),如果用戶未定義拷貝構(gòu)造函數(shù),則會(huì)調(diào)用默認(rèn)拷貝構(gòu)造函數(shù)。
先看一個(gè)例子,有一個(gè)學(xué)生類,數(shù)據(jù)成員時(shí)學(xué)生的人數(shù)和名字:
- #include <iostream>
- using namespace std;
- class Student
- {
- private:
- int num;
- char *name;
- public:
- Student();
- ~Student();
- };
- Student::Student()
- {
- name = new char(20);
- cout << 'Student' << endl;
- }
- Student::~Student()
- {
- cout << '~Student ' << (int)name << endl;
- delete name;
- name = NULL;
- }
- int main()
- {
- {// 花括號讓s1和s2變成局部對象,方便測試
- Student s1;
- Student s2(s1);// 復(fù)制對象
- }
- system('pause');
- return 0;
- }
這是由于編譯系統(tǒng)在我們沒有自己定義拷貝構(gòu)造函數(shù)時(shí),會(huì)在拷貝對象時(shí)調(diào)用默認(rèn)拷貝構(gòu)造函數(shù),進(jìn)行的是淺拷貝!即對指針name拷貝后會(huì)出現(xiàn)兩個(gè)指針指向同一個(gè)內(nèi)存空間。
所以,在對含有指針成員的對象進(jìn)行拷貝時(shí),必須要自己定義拷貝構(gòu)造函數(shù),使拷貝后的對象指針成員有自己的內(nèi)存空間,即進(jìn)行深拷貝,這樣就避免了內(nèi)存泄漏發(fā)生。
添加了自己定義拷貝構(gòu)造函數(shù)的例子:
- #include <iostream>
- using namespace std;
- class Student
- {
- private:
- int num;
- char *name;
- public:
- Student();
- ~Student();
- Student(const Student &s);//拷貝構(gòu)造函數(shù),const防止對象被改變
- };
- Student::Student()
- {
- name = new char(20);
- cout << 'Student' << endl;
- }
- Student::~Student()
- {
- cout << '~Student ' << (int)name << endl;
- delete name;
- name = NULL;
- }
- Student::Student(const Student &s)
- {
- name = new char(20);
- memcpy(name, s.name, strlen(s.name));
- cout << 'copy Student' << endl;
- }
- int main()
- {
- {// 花括號讓s1和s2變成局部對象,方便測試
- Student s1;
- Student s2(s1);// 復(fù)制對象
- }
- system('pause');
- return 0;
- }
3.淺拷貝帶來問題的本質(zhì)在于析構(gòu)函數(shù)釋放多次堆內(nèi)存,使用std::shared_ptr,可以完美解決這個(gè)問題。
關(guān)于std::shared_ptr的原理和實(shí)現(xiàn)可參考:C++筆試題之smart pointer的實(shí)現(xiàn)
一個(gè)完整的自定義類實(shí)現(xiàn)可參考:C++筆試題之String類的實(shí)現(xiàn)