[英]Copy constructor + Shallow & deep copy
我想問一下,當我沒有顯式編寫任何復制構造函數時,編譯器會自動生成默認執行淺拷貝的復制構造函數,對嗎? 所以在 main() 程序中,當我更改整數 a、b 和指針 p 的值時,在復制的 object 中,只有 p 的值發生變化,而 a 和 b 的值保持不變。為什么 a 和 b 的值沒有改變也? 我的代碼是:
#include <iostream>
#include <string.h>
using namespace std;
class Dummy {
private:
int a, b;
int *p;
public:
Dummy() {
p = new int;
}
void setData(int x, int y, int z) {
a = x;
b = y;
*p = z;
}
void showData() {
cout << "a = " << a << " b = " << b;
cout << " p = " << *p << endl;
}
~Dummy() {
delete p;
}
};
int main() {
Dummy d1;
d1.setData(3, 4, 5);
Dummy d2 = d1;
d1.showData();
d2.showData();
d1.setData(6, 7, 8);
d1.showData();
d2.showData();
return 0;
}
我程序的output是:
a = 3 b = 4 p = 5
a = 3 b = 4 p = 5
a = 6 b = 7 p = 8
a = 3 b = 4 p = 8
我的意思是,當我更改 object d1 的值時 object d2 的指針發生變化,那么為什么 object d2 的 a 和 b 的值也沒有改變?
此外,我在析構函數中使用 delete 關鍵字來刪除動態分配的指針:
~Dummy() {
delete p;
}
但它反而讓我的程序崩潰了。 這是為什么?
你完全弄錯了 - The idea of shallow copy
。 實際上, c++
本身並沒有內置所謂deep copy
。 所以,調用shallow copy
a bit wrong
。 shallow copy
這些詞的使用也造成了很多confusion
。
現在,讓我解釋一下,當cpp
initialization using assignment
時會發生什么。 cpp
或c
(在復制結構時)有一個稱為bitwise copy
的概念。 在這個概念中, all the member variables of one object(struct object/class object - you can say either) is identically copied to another object
。 現在, both objects point to same memory location
是totally wrong idea
。 實際上, both object
都有自己own memory location
,當然, their variables
占用different memory spaces
。 對於你,我已經寫了一些關於 memory 的測試。你會完全理解,如果你只看到測試,它是 output:
#include <iostream>
#include <string.h>
using namespace std;
class Dummy {
int a, b;
int *p;
public:
Dummy() {
p = new int;
}
void setData(int x, int y, int z) {
a = x;
b = y;
*p = z;
}
void showData() {
cout << "a = " << a << " b = " << b;
cout << " p = " << *p << endl;
cout << endl; // an extra new line for readability of output
}
void showMemory() {
cout << "addr(a) = " << &a << " addr(b) = " << &b;
cout << " addr(p) = " << &p << endl;
}
~Dummy() {
*p = 100;
delete p;
}
};
// testing memory
void memoryTest() {
cout << "testing d1:" << endl;
Dummy d1;
d1.setData(3, 4, 5);
cout << "addr(d1) = " << &d1 << endl;
d1.showMemory();
cout << endl ;
cout << "testing d2:" << endl;
Dummy d2 = d1;
cout << "addr(d2) = " << &d2 << endl;
d2.showMemory();
}
int main() {
// memoryTest
memoryTest();
return 0;
}
測試的 output 是:
testing d1:
addr(d1) = 0x6dfed4
addr(a) = 0x6dfed4 addr(b) = 0x6dfed8 addr(p) = 0x6dfedc
testing d2:
addr(d2) = 0x6dfec8
addr(a) = 0x6dfec8 addr(b) = 0x6dfecc addr(p) = 0x6dfed0
這清楚地表明, d1
和d2
這兩個對象占用的memory是完全不同的。
*p=8
時,它同時影響d1
和d2
? : 當你賦值時, Dummy d2 = d1;
,我們可能會說發生了如下情況(盡管應用按位復制時實際上並沒有發生,只是為了清楚起見):
d2.p = d1.p
因此,我們知道, d1.p
和d2.p
包含相同的 memory 位置(注意:d1.p 是一個指針。因此,它不包含任何 integer,而是包含一個 int 的 memory 地址)。
因此,當您編寫*p = 8
時,您是在告訴程序將 go 指向 p 定位的 memory 位置,並將該 memory 位置的值更改為 8。(請注意,此處,您沒有更改d1.p
, d1.p
仍然包含相同的 memory 位置。相反,您只是將 memory 位置的內容從 5 更改為 8)。 這就是為什么當您調用d2.p
時,您會得到更改后的值。 因為, d2.p
包含與 d1.p 相同的d1.p
位置。
p
時代碼會崩潰? :現在,讓我先問你,你能釋放一個 memory 已經釋放的東西嗎? 您可以編寫代碼,但行為未定義。 它可能會使您的程序崩潰,也可能什么都不做。
好吧,在Dummy
destructor
中你寫了delete p;
. 現在, d2
或d1
將首先被銷毀。 假設d2
first
被銷毀。 所以,當d2's
destroyer 被調用時, p
被freed
了。 然后, d1's
破壞者將被調用,它也會嘗試free p
。 但是p
已經被釋放了。 在您的情況下,程序因此而崩潰。
希望,你現在一切都清楚了。
如果我上面描述的有什么不明白的地方,請提出問題,我也會盡力回答。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.