写时拷贝引用计数器模型

1、深浅拷贝的使用时机:

专注于为中小企业提供成都做网站、网站设计、外贸营销网站建设服务,电脑端+手机端+微信端的三站合一,更高效的管理,为中小企业叙永免费做网站提供优质的服务。我们立足成都,凝聚了一批互联网行业人才,有力地推动了成百上千家企业的稳健成长,帮助中小企业通过网站建设实现规模扩充和转变。

  浅拷贝:对只读数据共用一份空间,且只释放一次空间;

  深拷贝:数据的修改,的不同空间;

2、引用计数器模型

  使用变量use_count,来记载初始化对象个数;

  static模型(此处只用浅拷贝与浅赋值)

#include
#include
#include
using namespace std;

class String{
public:
    String(const char *str = ""){
        if(str == NULL){
            data = new char;
            data[0] = 0;
        }else{
            data = new char[strlen(str) + 1];
            strcpy(data,str);
        }
        use_count++;     //每新创建一个对象,对引用计数器++;
    }
    String(const String &s){
        data = s.data;
        use_count++;      //创建出新的对象,use_count++;
    }
 //此处先不写赋值语句
    ~String(){
        if(--use_count == 0){  //当引用计数器减为0时,就是每次行析构对象时,都对它减一次,直到为0才释放空间,
            delete []data;
            data = NULL;
        }
    }
public:
    char* GetString()const{
        return data;
    }
private:
    char *data;
    static int use_count;   //此处use_count只有一份,负责记载创建了多少个对象;
};

int String::use_count = 0;  //C++中的静态变量全局只有一份,可以再类外进行初始化;

int main(void)
{
    String s1("hello");
    cout<

  上面的static浅拷贝其实存在很大的问题,当t3对象创建时,use_count会加1;

  当调用析构函数时,每次减1,为0时,释放空间,

写时拷贝 引用计数器模型

3、写时拷贝

  浅拷贝与深拷贝联合使用,看实际需求对其编写,此时我希望,对数据读时共用一份数据,需要修改时,在单独开辟空间进行修改,在进行改写,并且对象(初始化)应该有自己的data和use_count,赋值语句时共用一份就行,此时就需要句柄了,这就是写时拷贝;

  具体完整代码如下:

#include
#include
#include
using namespace std;
class String;
class String_rep{        // 这个类是封装在内部供我们程序员自己使用的。
    friend class String;  //友元类,可以访问私有数据。
public:
    String_rep(const char *str = ""):use_count(0){  //构造函数的初始化
        if(str == NULL){
            data = new char[1];
            data[0] = 0;
        }else{
            data = new char[strlen(str)+1];
            strcpy(data,str);
        }
    }
    String_rep(const String_rep &rep);
    String_rep& operator=(const String_rep &rep);
    ~String_rep(){
        delete []data;
        data = NULL;
    }
public:
    void increment(){  
        use_count++;
    }
    void decrement(){   //这个函数至关重要,写了一个释放空间的函数,要在其后赋值语句中使用;
        if(--use_count == 0)
            delete this;
    }
    int use_count_()const{
        return use_count;
    }
public:
    char *getdata()const{
        return data;
    }
private:
    char *data;
    int use_count;
};
class String{
public:
    String(const char *str = ""):rep(new String_rep(str)){
        rep->increment();
    }
    String(const String &s){
        rep = s.rep;
        rep->increment();
    }
    String& operator=(const String &s){
        if(this != &s){
            rep->decrement();
            rep = s.rep;
            rep->increment();
        }
        return *this;
    }
    ~String(){
        rep->decrement();
    }
public:
    int use_count()const{
        return rep->use_count_();
    }
    void print()const{
        cout<data<use_count_() > 1){ //对象个数大于1才进行拷贝出来重新写,只有一个就直接在其上进行修改。
            String_rep *new_rep = new String_rep(rep->data);
            this->rep->decrement();
            rep = new_rep;
            rep->increment();
        }
        char *pch = rep->data;
        while(*pch){
            *pch -= 32;
            pch++;
        }
    }
private:
    String_rep *rep; // 句柄
};
int main(){
    String s1("hello");
    String s2 = s1;
    String s3("xyz");
    s3 = s2;
    s1.toupper();
    s1.print();
    cout<<"s1 count = "<

以上的代码就可以达到目的,每次创建对象都有自己的data和use_count(调用构造函数),在赋值语句时先释放原有空间,在进行浅拷贝,构造函数时也是浅拷贝,对其进行了各自空间的管理与释放,并且在修改数据时拷贝出来一份即可。

写时拷贝 引用计数器模型

分析如下:

写时拷贝 引用计数器模型

关于以上还有个问题:就是:

void decrement(){   
  if(--use_count == 0)
   delete this;
}

为什么不在String类的析构函数中写delete呢?

原因:析构函数只有在对象释放是才调用,而在此时,通过赋值语句要释放空间,析构函数此时就不能及时释放原有空间,会造成内存泄漏,所以写一个释放空间的函数,内部有delete,会先调用析构函数,达到了及时释放空间的目的!

以上只是对写时拷贝的粗浅理解。


网站标题:写时拷贝引用计数器模型
转载源于:http://myzitong.com/article/jgesod.html