c++中的深淺拷貝

**一、淺拷貝:**

1)代碼:
1、構造:

String ::String(const char* str="")
       :_str(new char[strlen(str)+1])
{
    strcpy(_str, str);
}

2、拷貝構造

String::String(const String&s)
       : _str(s._str)
{}

3、賦值淺拷貝

//s2==s1
String& String:: operator=(const String&s)
{
    if (this!=&s)
    {
        _str = s._str;
    }
    return *this;
}

2)圖解:這裏寫圖片描述

4、析構

String::~String()
{
    if (_str)
    {
        delete[] _str;
    }
}

由於淺拷貝會引發析構兩次的問題 所以引入了引用計數,爲了保證證每個對象的獨立性,所以引入了寫時拷貝,可以理解爲引用計數和寫時拷貝就是淺拷貝的一種優化。
二、引用計數與寫時拷貝:
1)代碼:
1、構造:

String::String(const char* str = "")//拷貝
        :_str(new char[strlen(str)+1])
        ,_pCount(new int(1))//開闢1塊空間並初始化爲1 
{
    strcpy(_str, str);
}

2、拷貝構造:

String::String(const String&s)//拷貝構造
:_str(s._str)
,_pCount(s._pCount)
{
    (*_pCount)++;
}

調試結果:
這裏寫圖片描述

圖解:
這裏寫圖片描述
問題:一個改了會影響另一個

String s1("hello world");
    String s2(s1);
    s1[2] = 'x';
    cout << s1.c_str() << endl;
    cout << s2.c_str() << endl;

調試結果:
這裏寫圖片描述

3、賦值運算符重載:

//s2=s1
String& String:: operator=(const String&s)//賦值運算符重載
{
    if (this != &s)
    {
        if (--(*_pCount) == 0)//這裏不調用析構函數,
            //因爲析構函數一般都是在出了函數作用域才被調用
        {
            delete[] _str;
            delete _pCount;
        }
        _str = s._str;
        _pCount = s._pCount;
        ++(*_pCount);
    }
    return *this;
}
String s1("hello world");
    String s2(s1);
    s1[2] = 'x';
    cout << s1.c_str() << endl;
    cout << s2.c_str() << endl;

調試結果:這裏寫圖片描述

圖解:
這裏寫圖片描述

4、寫時拷貝(下開法):

void String::CopyOnWrite()
{
    if ((*_pCount) > 1)
    {
        char*newstr = new char[strlen(_str) + 1];
        strcpy(newstr, _str);
        _str = newstr;
        --(*_pCount);
        _pCount = new int(1);
    }
}
 char& String::operator[](size_t pos)//可以修改字符串中的字符
{
    CopyOnWrite();
    return _str[pos];
}

爲了解決兩個程序會相互影響
調試結果:
這裏寫圖片描述
圖解:
這裏寫圖片描述

5、析構:

String::~String()
{
    if (--(*_pCount)==0)
    {
        delete[] _str;
        delete _pCount;
        _str = NULL;
        _pCount = NULL;
    }
}

三、深拷貝(傳統寫法和現代寫法)
傳統寫法:

String::String(const char*str = "")
:_str(new char[strlen(str) + 1])
{
    strcpy(_str, str);
}
//s2(s1)
String::String(const String& s)
        : _str(new char[strlen(s._str)+1])
{
    strcpy(_str, s._str);
}
//s3=s1
String& String::operator=(const String&s)
{
    if (this!=&s)
    {
        char*str = new char[strlen(_str) + 1];
        delete[] _str;
        _str = str;
        strcpy(_str, s._str);
    }
    return *this;
}
String::~String()
{
    if (_str)
    {
        delete[] _str;
    }
}

調試結果:
這裏寫圖片描述
圖解:
這裏寫圖片描述
現代寫法:

String::String(const char*str = "")
:_str(new char[strlen(str) + 1])
{
    strcpy(_str, str);
}
//s2(s1)
String::String(const String& s)
: _str(NULL)
{
    String tmp(s._str);
    swap(tmp._str, _str);
}
//s1=s3
String& String::operator=(const String&s)
{
    if (this != &s)
    {
        String tmp(s._str);
        swap(_str, tmp._str);
    }
    return *this;
}
String::~String()
{
    if (_str)
    {
        delete[] _str;
    }
}


調試結果:
這裏寫圖片描述
圖解:
這裏寫圖片描述
補充寫時拷貝(頭開法):

String::String(const char* str = "")
:_str(new char[strlen(str)+5])
{
    _str += 4;
    strcpy(_str, str);
    *((int*)(_str-4)) = 1;
}
//s2(s1)
String::String(const String& s)
:_str(s._str)
{
    *((int*)(_str-4)) += 1;
}
//s1=s2
String& String ::operator=(const String& s)
{
    if (this!=&s)
    {
        if (--(*(int*)(_str - 4)) == 0)
        {
            delete[](_str - 4);
        }
        _str = s._str;
        ++(*(int*)(_str - 4));
    }
    return *this;
}
void String::CopyOnWrite()
{
    if ((*(int*)(_str-4))>1)
    {
        char* newstr = new char[strlen(_str) + 5];
        strcpy(newstr, _str);
        --(*(int*)(_str - 4));
        _str = newstr;
        ++(*(int*)(_str - 4));

    }

}
char &String::operator[](size_t pos)
{
    CopyOnWrite();
    return _str[pos];
}
String::~String()
{
    if (--(*(int*)(_str-4))==0)
    {
        delete[] (_str-4);
    }
}

引用計數導致的改一塊兩塊一塊改的問題
引用計數導致的改一塊兩塊一塊改
寫時拷貝:
調試結果:
這裏寫圖片描述
圖解:
這裏寫圖片描述

發佈了66 篇原創文章 · 獲贊 19 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章