写时拷贝(stl string类与自实现小例子。。。

何为写时拷贝

  写时才拷贝(Copy-On-Write)技术,就是编程界“懒惰行为”——拖延战术的产物。类似的的“懒惰行为”有:数据库的懒惰删除和redis中的SDS结构等。

  如果对拷贝的数据时只读,则为浅拷贝,当要对数据进行写时,才真正的拷贝原数据的副本,即深拷贝

下面是一个STL string类写时拷贝的实例:

#include <iostream>
#include <string>
#include <stdio.h>
using namespace std;

int main(int argc, char *argv[])
{
    string str1 = "hello world\n";
    string str2 = str1;

    printf("str1:%x  str2:%x\n", str1.c_str(), str2.c_str());
    str2.clear();
    str2 = "hello\n";
    printf("str1:%x  str2:%x\n", str1.c_str(), str2.c_str());
    return 0;
}

运行结果如下:


当对str2对象进行clear()与再赋值时,才开辟新的空间。

而通常写时拷贝是如何实现的呢?

下面是一个小例子:(使用“引用计数”方法)

#include<iostream>
#include<cstring>
#include<cstdlib>
using namespace std;
typedef struct sdshdr{
    //  记录buf数组中已使用的字节数
    int len;
    // 记录buf数组中为使用的字节数
    int free;
    // 用于保存字符串
    char buf[];
}SDS;
SDS* sdsnewlen(const char* init, size_t len){
    struct sdshdr* sh;
    sh = (struct sdshdr*)malloc(2*sizeof(int)+(len+1)*sizeof(char));
    // 内存分配失败,返回
    if (sh == NULL) return NULL;
    // 设置初始化长度
    sh->len = len;
    // 新 sds 不预留任何空间
    sh->free = 0;
    // 如果有指定初始化内容,将它们复制到 sdshdr 的 buf 中
    // T = O(N)
    if (len && init)
        memcpy(sh->buf, init, len);
    // 以 \0 结尾
    sh->buf[len] = '\0';
    // 返回 buf 部分,而不是整个 sdshdr
    return sh;
}
SDS* sdsnew(const char* init){
    size_t init_len = (init == NULL) ? 0 : strlen(init);
    return sdsnewlen(init, init_len);
}
void sdsfree(SDS* s){
    free(s);
}
class Dynamic_String{
    private:
        SDS* s;
        int* count;
    public:
        Dynamic_String(const char* str = ""){
            s = sdsnew(str);
            count = new int;
            *count = 1;
        }
        // 拷贝构造函数
        Dynamic_String(const Dynamic_String& ds){
            s = ds.s;
            count = ds.count;
            (*count)++;
            cout<<"copy count:"<<*count<<endl;
        }
        // 赋值构造函数
        Dynamic_String& operator=(const Dynamic_String& ds){
            cout<<"operator="<<endl;
            // 是否指向同一内存地址
            if(s != ds.s){
                // 原对象是否要释放
                if(--(*count) == 0){
                    sdsfree(s);
                    free(count);
                }
                s = ds.s;
                count = ds.count;
                (*count)++;
            }
            return *this;
        }
        ~Dynamic_String(){
            (*count)--;
            if(*count == 0){
                sdsfree(s);
                free(count);
                cout<<"delete ~"<<endl;
            }
        }
        //重载[]运算符
        char& operator[](int pos){
            CopyOnwrite(); //写时拷贝
            return s->buf[pos];
        }
        void CopyOnwrite(){
            if(*count > 1){ //需要拷贝
                cout<<"CopyOnWrite"<<endl;
                struct sdshdr* sh =(struct sdshdr*)malloc(2*sizeof(int)+sizeof(char)*strlen(s->buf));
                memcpy(sh->buf, s->buf, strlen(s->buf)+1);
                sh->free = s->free;
                sh->len =s->len;
                (*count)--;
                // 新的 空间 新的 引用计数器
                this->s = sh;
                count = new int(1);
            }
        }
};
int main(int argc, char *argv[]){
    Dynamic_String ds("abcdefg");
    Dynamic_String dst = ds;
    cout<<ds[1]<<endl;
    ds[1] = 'l';
    cout<<ds[1]<<endl;
    cout<<dst[1]<<endl;
   // cout<<sizeof(ds)<<endl;
    return 0;
}

运行结果:




发布了15 篇原创文章 · 获赞 3 · 访问量 2234

猜你喜欢

转载自blog.csdn.net/sky_s_limit/article/details/80325822