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);
    }
}

引用计数导致的改一块两块一块改的问题
引用计数导致的改一块两块一块改
写时拷贝:
调试结果:
这里写图片描述
图解:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/adzn1/article/details/79867244