String类的实现(4)写时拷贝浅析

由于释放内存空间,开辟内存空间时花费时间,因此,在我们在不需要写,只是读的时候就可以不用新开辟内存空间,就用浅拷贝的方式创建对象,当我们需要写的时候才去新开辟内存空间。这种方法就是写时拷贝。这也是一种解决由于浅拷贝使多个对象共用一块内存地址,调用析构函数时导致一块内存被多次释放,导致程序奔溃的问题。这种方法同样需要用到引用计数:使用int *保存引用计数;采用所申请的4个字节空间。String类的实现(4)写时拷贝浅析

 #include<iostream>
 #include<stdlib.h>
 using namespace std;
 class String
 {
 public:
     String(const char *pStr = "")
     {
         if (pStr == NULL)
         {
             _pStr =  + ];
             *((;
             _pStr = ();
             *_pStr = '\0';
         }
         else
         {
             _pStr =  + ];
             my_strcopy(_pStr, pStr);
             *(() = ;
         }
     }

     String(const String& s)
         :_pStr(s._pStr)
     {
         ++GetCount();
     }

     ~String()
     {
         Release();
     }

     String& operator=(const String& s)
     {
         if (this != &s)
         {
             Release();
             _pStr = s._pStr;
             --(GetCount());
         }
         return *this;
     }

     char& operator[](size_t index)//写时拷贝
     {
         )      //当引用次数大于1时新开辟内存空间
         {
              + ];
             my_strcopy(pTem + , _pStr);
             --GetCount();       //原来得空间引用计数器减1
             _pStr = pTem + ;
             GetCount() = ;
         }
         return _pStr[index];
     }
     const char& operator[](size_t index)const
     {
         return _pStr[index];
     }
    friend ostream& operator<<(ostream& output, const String& s)
    {
         output << s._pStr;
         return output;
    }
 private:
     int& GetCount()
     {
         );
     }
     void Release()
     {
          == --GetCount()))
         {
             _pStr = ();
             delete _pStr;
         }
     }

     char *_pStr;
 };

 int main()
 {
     String s1;
     String s2 = ";
     String s3(s2);
     s2[] = ';
     String s4;
     s3 = s4;
 } 

写时拷贝能减少不必要的内存操作,提高程序性能,但同时也是一把双刃剑,如果没按 stl 约定使用 String ,可能会导致极其严重的 bug ,而且通常是很隐蔽的,因为一般不会把注意力放到一个赋值语句。修改 String 数据时,先判断计数器是否为 0( 0 代表没有其他对象共享内存空间),为 0 则可以直接使用内存空间(如上例中的 s2 ),否则触发写时拷贝,计数 -1 ,拷贝一份数据出来修改,并且新的内存计数器置 0 ; string 对象析构时,如果计数器为 0 则释放内存空间,否则计数也要 -1 。

写时拷贝存在的线程安全问题

线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。 线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据。String类写时拷贝可能存在的问题详见:http://blog.csdn.net/haoel/article/details/24077

上一篇:高质量C++/C编程指南(林锐)


下一篇:css基础之 语法