簡體   English   中英

拷貝構造函數+淺拷貝和深拷貝

[英]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時會發生什么。 cppc (在復制結構時)有一個稱為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 locationtotally 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

這清楚地表明, d1d2這兩個對象占用的memory是完全不同的。

  1. 現在,您可能還有另一個問題:那么,為什么當我寫*p=8時,它同時影響d1d2 :

當你賦值時, Dummy d2 = d1; ,我們可能會說發生了如下情況(盡管應用按位復制時實際上並沒有發生,只是為了清楚起見):

d2.p = d1.p

因此,我們知道, d1.pd2.p包含相同的 memory 位置(注意:d1.p 是一個指針。因此,它不包含任何 integer,而是包含一個 int 的 memory 地址)。

因此,當您編寫*p = 8時,您是在告訴程序將 go 指向 p 定位的 memory 位置,並將該 memory 位置的值更改為 8。(請注意,此處,您沒有更改d1.pd1.p仍然包含相同的 memory 位置。相反,您只是將 memory 位置的內容從 5 更改為 8)。 這就是為什么當您調用d2.p時,您會得到更改后的值。 因為, d2.p包含與 d1.p 相同的d1.p位置。

  1. 現在,可能還有一個問題:為什么在析構函數中釋放p時代碼會崩潰? :

現在,讓我先問你,你能釋放一個 memory 已經釋放的東西嗎? 您可以編寫代碼,但行為未定義。 它可能會使您的程序崩潰,也可能什么都不做。

好吧,在Dummy destructor中你寫了delete p; . 現在, d2d1將首先被銷毀。 假設d2 first被銷毀。 所以,當d2's destroyer 被調用時, pfreed了。 然后, d1's破壞者將被調用,它也會嘗試free p 但是p已經被釋放了。 在您的情況下,程序因此而崩潰。

希望,你現在一切都清楚了。

如果我上面描述的有什么不明白的地方,請提出問題,我也會盡力回答。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM