中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C++中淺拷貝、深拷貝、寫時拷貝的示例分析

發布時間:2021-06-12 16:42:40 來源:億速云 閱讀:150 作者:小新 欄目:編程語言

小編給大家分享一下C++中淺拷貝、深拷貝、寫時拷貝的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

對于普通的類型來說,拷貝沒什么大不了的。

int a = 0;int b = a;

不會出現任何問題。

而類對象與普通對象不同,類對象內部結構一般較為復雜,存在各種成員變量。

淺拷貝

首先來說說我們常遇到的淺拷貝的情況。

#include <stdio.h> class student
{public:
    student()      // 構造函數,p指向堆中分配的一空間
    {
        _name = new char(100);        printf("默認構造函數\n");
    }
    ~student()     // 析構函數,釋放動態分配的空間
    {        if (_name != NULL)
        {            delete _name;
            _name = NULL;            printf("析構函數\n");
        }
    }private:    char * _name;     // 一指針成員};int main()
{
    student a;
    student b(a);   // 復制對象
    return 0;
}

這段代碼乍看之下沒什么毛病,通過類的默認構造函數將 a 復制給 b ,但是一旦運行就會程序崩潰
經過我的刻苦學習與鉆研,終于發現其中的問題所在。
由于我的類沒有拷貝構造函數,所以student b(a)會調用,編譯器自動生成的一個默認拷貝構造函數,該構造函數完成對象之間的位拷貝。位拷貝又稱淺拷貝
淺拷貝

  • 淺拷貝只是拷貝了指針,并沒有創建新的空間,使得兩個指針指向同一個地址,這樣在對象塊結束,調用函數析構的時,會造成同一份資源析構2次,即delete同一塊內存2次,造成程序崩潰。

  • 淺拷貝使得 a 和 b 指向同一塊內存,任何一方的變動都會影響到另一方。

  • 由于 a 和 b 指向的是同一塊內存空間,當 a 釋放了后,b 指向的內存空間不復存在,所以會出現內存泄露的情況。

如何避免淺拷貝害人呢?
養成自定義拷貝構造函數的習慣,當顯式定義了拷貝構造函數后,編譯器就會調用拷貝構造函數了,為了不出現程序崩潰,請使用自定義拷貝構造函數,當然我們自己如果把代碼寫成了淺拷貝的形式,那也不是不可能的事。

深拷貝

// 使用自定制拷貝構造函數,完成深拷貝!!!class A
{public:
    A()      // 構造函數,p指向堆中分配的一空間
    {
        m_pdata = new char(100);        printf("默認構造函數\n");
    }

    A(const A& r)    // 拷貝構造函數
    {
        m_pdata = new char(100);    // 為新對象重新動態分配空間
        memcpy(m_pdata, r.m_pdata, strlen(r.m_pdata));        printf("copy構造函數\n");
    }

    ~A()     // 析構函數,釋放動態分配的空間
    {        if (m_pdata != NULL)
        {            delete m_pdata;            printf("析構函數\n");
        }
    }private:    char *m_pdata;     // 一指針成員};int main()
{
    A a;
    A b(a);   // 復制對象
    return 0;
}

在拷貝構造函數中,為 b 對象 new 了一個新的空間,這樣 a 和 b 指向的是不同的空間,只是內容一致,但是互不影響。
重復的去開辟空間和釋放空間效率是很低的,聰明的地球人決定使用寫時拷貝。

寫時拷貝

寫時拷貝:引入一個計數器,每片不同內容的空間上都再由一個計數器組成,在構造第一個類指向時,計數器初始化為1,之后每次有新的類也指向同一片空間時,計數器加 1 ;在析構時判斷該片空間對應計數器是否為1,為1則執行清理工作,大于1則計數器減 1 。如果有需要進行增刪等操作時,再拷貝空間完成,有利于提高效率。

class String
{
public:
    String(const char* str = "")
        :_str(new char[strlen(str) + 1 + 4])//+1表示字符串后面要放一個'\0',+4表示多開辟一個空間存放引用計數
    {        _str += 4;//_str指向數據存放區
        strcpy(_str, str);        _GetCount() = 1;
    }
    String(const String& s)
        :_str(s._str)
    {        _GetCount()++;
    }
    String& operator=(String& s)
    {        if (this != &s)
        {            if (--_GetCount() == 0)
            {
                delete[](_str - 4);
            }
            ++s._GetCount();            _str = s._str;
        }        return *this;
    }
    ~String()
    {        if (--_GetCount() == 0)
        {
            delete[](_str - 4); // 注意:由于計數器存放在了_str首地址-4的地址上,所以在析構時一定要注意全部釋放,避免內存泄漏。
        }
    }
public:    int& _GetCount()
    {        return *((int*)_str - 1);
    }
private:    char* _str;

};

以上是“C++中淺拷貝、深拷貝、寫時拷貝的示例分析”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

c++
AI

英山县| 五原县| 临江市| 九龙城区| 封丘县| 财经| 鄢陵县| 景洪市| 沅江市| 扬州市| 通山县| 双峰县| 西宁市| 栖霞市| 贡嘎县| 威远县| 乌鲁木齐市| 阜宁县| 钟山县| 清原| 安宁市| 辛集市| 谢通门县| 弋阳县| 酒泉市| 上虞市| 衡水市| 平罗县| 嘉黎县| 威信县| 临澧县| 丹江口市| 新乡县| 五原县| 永胜县| 龙海市| 佛学| 琼海市| 青州市| 姜堰市| 陇西县|