假設現在有一片源記憶體空間,和乙個待分配引用的目標物件記憶體空間,目的是給目標物件空間分配記憶體。而定義簡而言之,深拷貝會複製源記憶體空間並重新生成一片記憶體空間,並將其引用給目標物件,而淺拷貝則正好相反,是直接將源記憶體空間引用給目標物件記憶體空間。
c++中用到拷貝的場景有以下三種:
1、函式引數中以值傳遞的方式傳入時,會將傳入的實際引數拷貝乙份
2、函式返回中返回了乙個區域性物件,會將其拷貝乙份並返回
3、再給乙個物件初始化的時候(不是賦值)會將值拷貝乙份。
之所以這個問題值得深究,肯定是因為如果不注意會引起嚴重的後果,尤其是在類成員中有指標的時候,比如以下例項:
class
string
string
(const
char
* str ="")
:_str
(new
char
[strlen
(str)+1
])string
(const string &s)
:_str
(null)~
string()
}private
:char
* _str;};
void
main()
}
這段**的執行結果是崩潰,並且可以看到建構函式被執行了兩次析構函式被執行了兩次。
我們一次一次地來分析
//第一次建構函式執行
string s1
("字串1");
//生成s2的時候第二次建構函式執行
string s2
(s1)
;//s1、s2兩個區域性物件被釋放的時候分別執行一次析構函式
出現崩潰的原因就是因為深淺拷貝函式被忽視,從而對同一片記憶體進行了兩次的析構。
繼續對上乙個例項分析,對同一片記憶體進行兩次析構意味著什麼,也就是說s2和s1是使用的同一片記憶體,為什麼會這樣,理由只可能是在「string s2(s1);」這句話中,s1將自己的記憶體引用給了s2。為什麼會這樣我們一步步來分析。
這句話中的動作拆分開來理解:1、要新生成s2就要呼叫string的建構函式;2、建構函式傳入的是乙個string型別,要呼叫拷貝建構函式,自定義的建構函式中並沒有定義拷貝建構函式,因此呼叫系統預設的拷貝建構函式。
//系統預設的拷貝建構函式
string (
const string& s)
從這裡可以看出,系統預設的拷貝建構函式只是將類成員指標指向了傳入的實參,因此用預設拷貝建構函式生成的新物件和源物件共享桶一片記憶體空間,至此真相大白。
結論:預設的拷貝建構函式使用的是淺拷貝,如果類成員有指標,會造成對同一片記憶體的多次釋放,從而崩潰。
第一種:
自定義拷貝建構函式,在拷貝建構函式中,重新分配出一片記憶體空間,讓新物件指向這片新劃的記憶體。
string (
const string&s)
第二種:
類成員指標使用智慧型指標shared_ptr。深淺拷貝問題的實質是同一片記憶體被多次釋放,使用智慧型指標可以有效避免這個問題。
當物件中存在指標成員時,除了在複製物件時需要考慮自定義拷貝建構函式,還應該考慮以下兩種情形:
1.當函式的引數為物件時,實參傳遞給形參的實際上是實參的乙個拷貝物件,系統自動通過拷貝建構函式實現;
2.當函式的返回值為乙個物件時,該物件實際上是函式內物件的乙個拷貝,用於返回函式呼叫處
C 深拷貝 淺拷貝
c 深拷貝 淺拷貝 深拷貝 淺拷貝和直接指向引用的區別 深拷貝 淺拷貝都是重新開闢了記憶體空間,並且在新的記憶體空間裡面賦了物件本身 的值。直接指向引用是乙個物件直接指向另外乙個物件的引用,這兩個物件指向的是同一 塊記憶體空間,操作任乙個物件都會影響另外的物件。深拷貝和淺拷貝的區別 如果物件的成員都...
C 淺拷貝 深拷貝
簡單的來說就是,在有指標的情況下,淺拷貝只是增加了乙個指標指向已經存在的記憶體,而深拷貝就是增加乙個指標並且申請乙個新的記憶體,使這個增加的指標指向這個新的記憶體,採用深拷貝的情況下,釋放記憶體的時候就不會出現 在淺拷貝時重複釋放同一記憶體 的錯誤!你正在編寫c 程式中有時用到,操作符的過載。最能體...
C 深拷貝 淺拷貝
include using namespace std class cexample void show 就類物件而言,相同型別的類物件是通過拷貝建構函式來完成整個複製過程的 include using namespace std class cexample cexample const cexa...