写时拷贝/写时复制技术

拷贝控制

C++提供两个拷贝控制函数

  • 拷贝构造函数
  • 拷贝赋值运算符重载

例如:String

class String{
public:
        String(const char* str = NULL);
        String(const String& str);
        String& operator=(const String& str);
        ~String();
        size_t size()const;
        friend ostream& operator<<(ostream& os,String const& str);
private:
        char* data;
};

C++11增加了移动构造函数和移动赋值运算符重载。

深拷贝与浅拷贝

概念

  • 浅拷贝:只拷贝指针地址
    通常默认拷贝构造函数与赋值运算符重载都是浅拷贝。

  • 深拷贝:重现分配堆内存拷贝指针指向内容

例如:String

String::String(const char* str){
        if(NULL == str){
                data = new char[1];
                data[0] = '\0';
        }else{
                data = new char[strlen(str)+1];
                strcpy(data,str);
        }

}
String::~String(){
        delete [] data;
        data = NULL;
}
String::String(const String& str){
        data = new char[str.size()+1];
        strcpy(data,str.data);
}
String& String::operator=(const String& str){
        if(this != &str){
                delete [] data;
                data = new char[str.size()+1];
                strcpy(data,str.data);
        }
        return *this;
}
inline size_t String::size()const{
        return strlen(data);
}

ostream& operator<<(ostream& os,const String& str){
        return os << static_cast<const void *>(str.data) << ':' << str.data;
}

测试代码

int main(){
        String s1("Hello World");
        String s2 = s1;
        String s3;
        s3 = s1;
        cout << s1 << endl;
        cout << s2 << endl;
        cout << s3 << endl;
}
比较

在这里插入图片描述

优点缺点
浅拷贝只有一份数据,节省空间。因为多个指针指向同一个空间,容易引发同一内存多次释放的问题。
深拷贝每个指针指向不同地址,没有同一内存多次释放的问题。存在多份相同数据,浪费空间。

浅拷贝与深拷贝的优缺点分别互为彼此的优缺点。有什么办法可以兼有二者的优点?

主要解决问题:

  1. 数据相同时只有一份内存。
  2. 不会出现多次释放问题。

计数器技术:数据相同共享一份内存

计数器技术就是兼有浅拷贝与深拷贝优点的一种技术。
在这里插入图片描述

在类声明中添加了计数器s_count。

class String{
public:
        String(const char* str = NULL);
        String(const String& str);
        String& operator=(const String& str);
        ~String();
        size_t size()const;
        friend ostream& operator<<(ostream& os,String const& str);
private:
        char* data;
        static int s_count;
};

实现中增加计数处理

int String::s_count = 0;
String::String(const char* str){
        if(NULL == str){
                data = new char[1];
                data[0] = '\0';
        }else{
                data = new char[strlen(str)+1];
                strcpy(data,str);
        }
        ++s_count;
}
String::~String(){
        if(--s_count == 0){
                delete [] data;
                data = NULL;
        }
}
String::String(const String& str):data(str.data){
        ++s_count;
}
String& String::operator=(const String& str){
        if(this != &str){
                data = str.data;
                ++s_count;
        }
        return *this;
}

问题:构造新对象的计数是几?计数器技术会导致构造新对象计数错误。
解决:每个空间应该具有自己的引用计数,而不能所有空间共享一个引用计数。

在这里插入图片描述

头文件

class String{
        struct StringBase{
                StringBase(const char* str);
                ~StringBase();
                char* data;
                int count;
        };
public:
        String(const char* str = NULL);
        String(const String& str);
        String& operator=(const String& str);
        ~String();
        size_t size()const;
        friend ostream& operator<<(ostream& os,String const& str);
private:
        StringBase* base;
};

实现

String::StringBase::StringBase(const char* str){
        if(NULL == str){
                data = new char[1];
                data[0] = '\0';
        }else{
                data = new char[strlen(str)+1];
                strcpy(data,str);
        }
        ++count;
}
String::StringBase::~StringBase(){
        if(--count == 0){
                delete [] data;
                data = NULL;
        }
}

String::String(const char* str){
        base = new StringBase(str);
}
String::~String(){

}
String::String(const String& str):base(str.base){
        base->count++;
}
String& String::operator=(const String& str){
        if(this != &str){
                base->count--;
                base = str.base;
                base->count++;
        }
        return *this;
}
inline size_t String::size()const{
        return strlen(base->data);
}

ostream& operator<<(ostream& os,const String& str){
        return os << static_cast<const void *>(str.base) << ':' << str.base->data;
}

写时拷贝技术

以上都是拷贝复制操作,如果字符串发生改变,那么才是真正的写时拷贝。
例如:实现+=操作

String& String::operator+=(const String& str){
        base.count--;
        // 一些具体操作...
        base = new StringBase();
        base.count++; 
        return *this;
}

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值