String类 (浅拷贝/深拷贝/写时拷贝)

浅拷贝是指当对象的字段值被拷贝时,字段引用的对象不会被拷贝。例如,如果一个对象有一个指向字符串的字段,并且我们对该对象做了一个浅拷贝,那么两个对象将引用同一个字符串。

存在问题:
如果源程序中没有显示定义拷贝构造函数,在进行对象的拷贝时,将调用系统默认的拷贝构造函数,这就使得两个对象指向了同一资源,而析构函数又在对象生命周期结束后可以释放空间,势必会两次返还空间,编译器就会报错。

这时就需要用到深拷贝了。

深拷贝的两种版本:

#define  _CRT_SECURE_NO_WARNINGS 1  

#include<iostream>
using namespace std;

//#if 0
class String
{
public:
    String(char *pStr = "")   //构造函数
    {
        if (NULL == pStr)
        {
            _pStr = new char[1];
            *_pStr = 0;
        }
        else
        {
            _pStr = new char[strlen(pStr) + 1];
            strcpy(_pStr, pStr);
        }
    }

    //简洁版

    ////拷贝构造函数 1
    //String(const String &s)
    //  :_pStr(new char[strlen(s._pStr) + 1])
    //{
    //  String temp(s._pStr);
    //  swap(_pStr, temp._pStr);
    //}


    ////拷贝构造函数 2
    //String(const String &s)
    //  :_pStr(NULL)
    //{
    //  _pStr = new char[1];
    //  String temp(s._pStr);
    //  swap(_pStr, temp._pStr);
    //}

    //普通版
    String(const String &s)
        :_pStr(new char[strlen(s._pStr) + 1])
    {
        strcpy(_pStr, s._pStr);
    }



    //赋值运算符重载 

    /*
    //由于pTemp在栈上,出了函数将销毁,故错误
    String &operator=(const String &s)//赋值运算符重载
    {
    if (this != &s)
    {
    char *pTemp = new char[strlen(s._pStr) + 1];//  pTemp在栈上
    strcpy_s(pTemp, strlen(s._pStr), s._pStr);
    //strcpy_s(_pStr, strlen(pStr), pStr);
    delete[] _pStr;
    _pStr = pTemp;
    }
    return *this;

    }
    */
    //赋值运算符重载 1
    /*
    String &operator=(const String &s)
    {
    //if (this != &s)   赋值运算符重载的反例,会造成一块空间多次释放
    //{
    //  _pStr = s._pStr;
    //}
    //return *this;
    if (this != &s)
    {
    String temp(s._pStr);//用S里面的字符串构造一个临时的temp
    swap(_pStr, temp._pStr);//交换两个指针
    }
    return *this;
    }
    */

    //赋值运算符重载 2
    String& operator=(const String& pStr)
    {
        if (this != &pStr)
        {
            //防止new开辟内存失败,丢失原来内存  
            char* ptr = new char[strlen(pStr._pStr) + 1];
            strcpy(ptr, pStr._pStr);
            delete[]_pStr;
            _pStr = ptr;
        }
        return *this;
    }


    ~String()    //析构函数
    {
        if (this != NULL)
        {
            delete[] _pStr;
            _pStr = NULL;//可有可无
        }
    }
    friend ostream& operator<<(ostream & _cout, const String&pStr);
private:
    char *_pStr;

};
//输出流重载
ostream& operator<<(ostream & _cout, const String&pStr)
{
    _cout << pStr._pStr << endl;
    return _cout;
}
void FunTest1()
{
    String s1("hello");
    cout << "s1=" << s1 << endl;
    String s2(s1);   //调用拷贝构造函数
    cout << "s2=" << s2 << endl;

}

void FunTest2()
{
    String s3("word");
    String s4;
    s4 = s3;         //调用赋值运算符重载
    cout << "s3=" << s3 << endl;
    cout << "s4=" << s4 << endl;
}
int main()
{
    FunTest1();
    FunTest2();
    getchar();
    return 0;
}
//#endif

这里写图片描述

1、开辟两个空间的计数,代码如下:

#include<iostream>
using namespace std;

class String
{
public:
    String(const char * pStr = "")//构造函数
        :_pCount(new int(1))  //_pCount初始化为1
    {
        if (NULL == pStr)
        {
            _pStr = new char[1];
            *_pStr = '\0';
        }
        else
        {
            _pStr = new char[strlen(pStr) + 1];
            strcpy(_pStr, pStr);
        }
    }
    String(const String &s)//拷贝构造函数
        :_pStr(s._pStr)
        , _pCount(s._pCount)
    {
        ++*_pCount;//调用一次拷贝构造函数_pCount++
    }
    //赋值运算符重载
    String & operator = (const String & s)
    {
        if (this != &s)
        {
            if (0 == --*_pCount)
            {
                delete[] _pStr;
                delete _pCount;
            }
            _pStr = s._pStr;
            _pCount = s._pCount;
            ++*_pCount;
        }
    }
    ~String()//调用析构函数时 先--_pCount,判断是否为0
    {
        if ((_pStr) && (0 == --*_pCount))
        {
            delete[] _pStr;
            _pStr = NULL;
            delete _pCount;
            _pCount = NULL;
        }
    }
    friend ostream& operator<<(ostream & output, const String &s);
private:
    char * _pStr;
    int * _pCount;
};
ostream& operator<<(ostream & output, const String &s)//输出流的重载
{
    output << s._pStr << endl;
    return output;
}
void FunTest()
{
    String s1("hello");
    cout << "s1=" << s1 << endl;
    String s2(s1);
    cout << "s2=" << s2 << endl;
    String s3("heihei");
    cout << "s3=" << s3 << endl;
    String s4 = s3;
    cout << "s4=" << s4 << endl;

}
int main()
{
    FunTest();
    getchar();
    return 0;
}

运行结果:
_pCount计数

2、一个空间的计数,代码如下:

class String
//{
//public:
//  String(char* ptr = NULL)
//  {
//      if (ptr == NULL)
//      {
//          _ptr = new char[5];
//          *(_ptr + 4) = 0;
//      }
//      else
//      {
//          _ptr = new char[strlen(ptr) + 5];
//          strcpy(_ptr + 4, ptr);
//      }
//      *(int*)_ptr = 1;
//  }
//  String(const String& s)
//      :_ptr(s._ptr)
//  {
//      (*(int*)_ptr)++;
//  }
//  String& operator=(const String& s)
//  {
//      if (&s != this)
//      {
//          _ptr = s._ptr;
//          (*(int*)_ptr)++;
//      }
//      return *this;
//  }
//  ~String()
//  {
//      if (--*(int*)_ptr == 0)
//      {
//          delete[] _ptr;
//          _ptr = NULL;
//      }
//  }
//private:
//  char* _ptr;
//};
class String
{
public:
    String(const char* pStr)
    {
        if (pStr == NULL)
            pStr = " ";

        _pStr = new char[strlen(pStr) + 1 + 4];//多开辟4个字节
        _pStr += 4;
        strcpy(_pStr, pStr);
        GetReference() = 1;
    }
    String(const String&s)
        :_pStr(s._pStr)
    {
        ++ GetReference();
    }
    String & operator = (const String & s)
    {
        if (this != &s)
        {
            if (--GetReference() = 0)
            {
                _pStr -= 4;
                delete[] _pStr;

            }
            _pStr = s._pStr;
            ++GetReference();
        }
    }
    ~String()
    {
        if ((--GetReference() == 0) && _pStr)
        {
            _pStr -= 4;
            delete[] _pStr;
            _pStr = NULL;
        }
    }
    friend ostream & operator<<(ostream &output, String &s);
private:
    int& GetReference()
    {
        return *(int*)(_pStr - 4);
    }
    char* _pStr;
};
ostream & operator<<(ostream &output, String &s)
{
    output << s._pStr << endl;
    return output;
}
void FunTest()
{
    String s1("ximenchuixue");
    cout << "s1=" << s1 << endl;
    String s2(s1);
    cout << "s2=" << s2 << endl;
    String s3("sikongzhaixing");
    cout << "s3=" << s3 << endl;
    String s4 = s3;
    cout << "s4=" << s4 << endl;

}
int main()
{
    FunTest();
    getchar();
    return 0;

}

运行结果:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章