String类的自我认知(浅拷贝、深拷贝、写时拷贝)

浅拷贝
1.浅拷贝是所有对象都共用一块空间,一个对象改变,所有对象都跟着改变,在调用析构函数的时候,也会发生错误,会释放已经释放的空间。

class String
{
public:
    String(const char* pstr = "")//构造函数
    {
        if (pstr == NULL)//字符串为空
        {
          _pstr=new char[1];
            *_pstr = '\0';
        }
        else//字符串不为空
        {
          _pstr = new char[strlen(pstr) + 1];
            strcpy(_pstr,pstr);
        }
    }
    String(const String &s)//拷贝构造
    {
        _pstr = s._pstr;
    }
    String& operator=(String& s)//赋值运算符的重载
    {
        if (_pstr != s._pstr)
        {
            _pstr = s._pstr;
        }
        return *this;
    }
    ~String()
    {
        if (_pstr == NULL)
            return;
        else
        {
            delete[]_pstr;
            _pstr = NULL;
        }
    }
private:
    char* _pstr;
};
void Funtest()
{
    String s1("abcd");
    String s2(s1);
    String s3 = s2;
    String s4;
    s4 = s3;
}
int main()
{
    Funtest();
    system("pause");
    return 0;
}

这里写图片描述
四个对象共用一块空间,接下来是调用析构函数,首先调用s4的析构函数,接下来再继续调用析构函数就会发生错误。
对于以上的程序,我们可以想用计数的方式,每次构造一个对象就使计数器+1,在调用析构的时候使计数器-1,当计数器值为0的时候再去释放空间,代码如下:

class String
{
public:
    String(const char* pstr = "")//构造函数
        ,_count(0)
    {
        if (pstr == NULL)//字符串为空
        {
          _pstr=new char[1];
            *_pstr = '\0';
        }
        else//字符串不为空
        {
        _pstr=new char[strlen(pstr) + 1];
            strcpy(_pstr, pstr);//将字符串的首地址复制过去
        }
        _count++;
    }
    String(String &s)//拷贝构造
    {
        _pstr = s._pstr;
        _count = s._count;
        _count++;
    }
    String& operator=(String& s)//赋值运算符的重载
    {
        if (_pstr != s._pstr)
        {
            _pstr = s._pstr;
            _count = s._count;
            _count++;
        }
        return *this;
    }
    ~String()
    {
        if (_pstr == NULL)
            return;
        else
        {
            if (--_count == 0)
            {
                delete[]_pstr;
                _pstr = NULL;
            }
        }
    }
private:
    char* _pstr;
    int _count;
};
void Funtest()
{
    String s1("abcd");
    String s2(s1);
    String s3 = s2;
    String s4;
    s4 = s3;
}
int main()
{
    Funtest();
    system("pause");
    return 0;
}

当创建对象完成时,每个对象中保存的_count的值是不一样的,如下:
这里写图片描述
进而当进行析构时,并不能使每个对象中的 _count的值都为0
这里写图片描述
由此我们会想到,当一个类有多个对象时,这些对象中的静态成员数据共用一块存储空间,可以使用静态的成员数据来存储对象的个数,每个对象中的计数器中的数据保持一致。

class String
{
public:
String(const char* pstr = "")//构造函数
    {
        if (pstr == NULL)//字符串为空
        {
          _pstr=new char[1];
            *_pstr = '\0';
        }
        else//字符串不为空
        {
            _pstr=new char[strlen(pstr) + 1];
            strcpy(_pstr, pstr);//将字符串的首地址复制过去
        }
        _count++;
    }
    String(String &s)//拷贝构造
    {
        _pstr = s._pstr;
        _count = s._count;
        _count++;
    }
    String& operator=(String& s)//赋值运算符的重载
    {
        if (_pstr != s._pstr)
        {
            _pstr = s._pstr;
            _count = s._count;
            _count++;
        }
        return *this;
    }
    ~String()
    {
        if (_pstr == NULL)
            return;
        else
        {
            if (--_count == 0)
            {
                delete[]_pstr;
                _pstr = NULL;
            }
        }
    }
private:
    char* _pstr;
    static int _count;
};
int String::_count = 0;
void Funtest()
{
    String s1("abcd");
    String s2(s1);
    String s3 = s2;
    String s4;
    s4 = s3;
}
int main()
{
    Funtest();
    system("pause");
    return 0;
}

但这样运行的结果也是不正确的,他会使_count的值为5,然而只调用4次析构函数,不能释放空间。
这里写图片描述
指针的形式:

class String
{
public:
        String(const char* pstr = "")//构造函数
        , _count(new int(0))
    {
        if (pstr == NULL)//字符串为空
        {
          _pstr=new char[1];
            *_pstr = '\0';
        }
        else//字符串不为空
        {
            _pstr=new char[strlen(pstr) + 1];
            strcpy(_pstr, pstr);//将字符串的首地址复制过去
        }
        *_count=1;
    }
    String(String &s)//拷贝构造
    {
        _pstr = s._pstr;
        _count = s._count;
        (*_count)++;
        cout << "String(String &s)" << endl;
    }
    String& operator=(String& s)//赋值运算符的重载
    {
        if (_pstr != s._pstr)
        {
            _pstr = s._pstr;
            _count = s._count;
            (*_count)++;
        }
        return *this;
    }
    ~String()
    {
        if (_pstr == NULL)
            return;
        else
        {
            if (--(*_count) == 0)
            {
                delete[]_pstr;
                delete _count;
                _pstr = NULL;
                _count = NULL;
            }
        }
    }
private:
    char* _pstr;
    int* _count;
};

深拷贝
深拷贝中每个对象并不占用同一块空间,而是各自有各自的空间,这样就不会互相影响而产生不必要的结果。
深拷贝普通版

class String
{
public:
    String(const char* pstr = "")
        :_pstr(new char[strlen(pstr)+1])
    {
        if (pstr == NULL)
        {
            *_pstr = '\0';
        }
        else
        {
            strcpy(_pstr,pstr);
        }
    }
    String(const String &s)
        :_pstr(new char[strlen(s._pstr) + 1])
    {
        strcpy(_pstr,s._pstr);
    }
    String& operator=(const String& s)
    {
        if (_pstr != s._pstr)
        {
            char* tmp = new char[strlen(s._pstr) + 1];
            tmp= s._pstr;
            delete[]_pstr;
            _pstr=tmp;
        }
        return *this;
    }
    ~String()
    {
        if (_pstr == NULL)
        {
            return;
        }
        else
        {
            delete[] _pstr;
            _pstr = NULL;
        }
    }
private:
    char* _pstr;
};

深拷贝简洁版

class String
{
    public:
                String(const char* pstr = "")
        {
            if (pstr == NULL)
            {
                _pstr = new char[1];
                *_pstr = '\0';
            }
            else
            {
                _pstr=new char[strlen(pstr) + 1];
                strcpy(_pstr, pstr);
            }
        }
        String(const String &s)
            :_pstr(new char[strlen(s._pstr) + 1])
        {
            strcpy(_pstr, s._pstr);
        }
        /* String(String &s)
            :_pstr(NULL)
        {
            String tmp(s._pstr);
            swap(_pstr,s._pstr);
        }*/
        //赋值运算符重载第一种方式
      String& operator=(String s)//不用对象的引用,不会占用同一块空间
        {
          //不用if判断
            swap(_pstr,s._pstr);
            return *this;
        }
        //赋值运算符重载第二种方式
        /*String& operator=(const String& s)//已经定义了拷贝构造函数
        {
            if (_pstr != s._pstr)
            {
                String tmp(s);//调用拷贝构造函数
                swap(_pstr,tmp._pstr);
            }
            return *this;
        }*/
      //赋值运算符重载第三种方式
        String& operator=(const String& s)//没有定义拷贝构造函数时
        {
            if (_pstr != s._pstr)
            {
                String tmp(s._pstr);//只能调用构造函数
                swap(_pstr, tmp._pstr);
            }
            return *this;
        }
        ~String()
        {
            if (_pstr == NULL)
            {
                return;
            }
            else
            {
                delete[] _pstr;
                _pstr = NULL;
            }
        }
    private:
        char* _pstr;
};
void Funtest()
{
    String s1("abcd");
    String s2(s1);
    String s3 = s2;
    String s4;
    s4 = s3;
}
int main()
{
    Funtest();
    system("pause");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值