由浅入深地分析 写时拷贝(Copy On Write)

深拷贝效率低,我们可以应引用计数的方式去解决浅拷贝中析构多次的问题。

首先要清楚写时拷贝是利用浅拷贝来解决问题!!

方案一

class String
{
private:
    char* _str;
    int _refCount;
};

方案一最不靠谱,它将用作计数的整形变量_refCount定义为类的私有成员变量,任何一个对象都有它自己的成员变量_refCount,它们互不影响,只要拷贝出了对象,_refCount大于了1,那么每个对象调用自己的析构函数时--_refCount不等于0,那么它们指向的那块内存都将得不到释放,无法达到我们要的效果。

由浅入深地分析 写时拷贝(Copy On Write)

//以下是对方案一的简单实现,大家可以结合上图感受到方案一的缺陷
 
#define _CRT_SECURE_NO_WARNINGS 1
 
#include<iostream>
using namespace std;
#include<assert.h>
 
class String
{
public:
    String(char* str = "")    //不能strlen(NULL)
      :_refCount(0)
    {
      _str = new char[strlen( str) + 1];
      strcpy(_str, str);
      _refCount++;
    }
    String(String &s)
      :_refCount( s._refCount)   
    {
      _str = s._str;
      _refCount++;
      s._refCount = _refCount;
       
      //这里虽然可以让两个对象的_refCount相等,
      //但如果超过两个对象的_str指针都指向同一块内存时,
      //就无法让所有对象的_refCount都保持一致
      //这是方案一的缺陷之一
    }
    ~String()
    {
      if (--_refCount == 0)
      {
            delete[] _str;
          _str = NULL;
          cout << "~String " << endl;
      }
    }
    friend ostream& operator<<( ostream& output, const String &s);
private:
    char* _str;
    int _refCount;
};
ostream& operator<<( ostream& output, const String & s)
{
    output << s._str;
    return output;
}
void Test()
{
    String s1("aaa");
    String s2(s1);
    String s3(s2);
    cout << s1 << endl;
    cout << s2 << endl;
    cout << s3 << endl;
}
int main()
{
    Test();
    system("pause");
    return 0;
}

方案二

class String
{
private:
    char* _str;
    static int count;
};

设置一个静态整形变量来计算指向一块内存的指针的数量,每析构一次减1,直到它等于0(也就是没有指针在指向它的时候)再去释放那块内存,看似可行,其实不然!

这个方案只适用于只调用一次构造函数、只有一块内存的情形,如果多次调用构造函数构造对象,新构造的对象照样会改变count的值,那么以前的内存无法释放会造成内存泄漏。

由浅入深地分析 写时拷贝(Copy On Write)

结合上图和下面的代码,我们可以清楚地看到该方案相比方案一的改善,以及缺陷

#define_CRT_SECURE_NO_WARNINGS 1
 
 
#include<iostream>
using namespace std;
#include<assert.h>
 
class String
{
public:
    String(char* str = "")    //不能strlen(NULL)
    {
      _str = new char[strlen( str) + 1];
      strcpy(_str, str);
 
      count++;
    }
    String(const String &s)
    {
      _str = s._str;
      count++;
       
    }
    String& operator=( String& s) 
    {
      _str = s._str;
      count++;
      return *this;
    }
    ~String()
    {
      if (--count == 0)
      {
            delete[] _str;
          _str = NULL;
          cout << "~String " << endl;
      }
    }
    friend ostream& operator<<( ostream& output, const String &s);
    friend istream& operator>>( istream& input, const String &s);
private:
    char* _str;
    static int count;
};
ostream& operator<<( ostream& output, const String & s)
{
    output << s._str;
    return output;
}
istream& operator>>( istream& input, const String & s)
{
    input >> s._str;
    return input;
}
 
int String::count = 0;      //初始化count
 
void Test()
{
    String s1("aaa");
    String s2(s1);
    String s3 = s2;
    cout << s1 << endl;
    cout << s2 << endl;
    cout << s3 << endl;
 
}
int main()
{
    Test();
    system("pause");
    return 0;
}

方案三

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/dd54fc1a18679ce79af4c004d4934f76.html