#include<iostream>
using namespace std;
 
class String;
ostream& operator<<(ostream &out, const String&s);
//引用计数器类
class String_rep 
{
    friend class String;
    friend ostream& operator<<(ostream &out, const String&s);
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) :use_count(0)
        {
            data = new  char[strlen(rep.data) + 1];
            strcpy(data, rep.data);
        }
        String_rep&  operator=(const String_rep &rep)
        {
            if (this != &rep)
            {
                delete[]data;
                data = new char[strlen(rep.data) + 1];
                strcpy(data, rep.data);
            }
            return *this;
        }
        ~String_rep()
        {
                delete[]data;
                data = NULL;
        }
public:
    void increase()
    {
        ++use_count;
    }
    
    void decrease()
    {
        if (use_count == 0)
        {
            delete this; //自杀行为    释放this所指的空间,在释放之前调动这个类的析构函数
        }
    }
private:
        char *data;
        int use_count;
};
////////////////////////////////////////////////////////////////////////////////////////
class String
{
     friend ostream& operator<<(ostream &out, const String&s);
public:
    String(const char* str = " ")
    {
        rep = new String_rep(str);
        rep->increase();
    }
    String(const String &s)
    {
        rep = s.rep;      //浅拷贝
        rep->increase();
    }
    String& operator=(const String &s)
    {
        if (this != &s)
        {
            rep->decrease();   //模拟delete
            rep = s.rep;           //模拟new
            rep->increase();      //模拟strcpy
            /*rep = s.rep;   //这会更改引用计数器指针 ,造成s内存泄漏
            rep->increase();*/
        }
        return *this;
    }
        ~String()
        {
            rep->decrease();
        }
public:
    void to_upper()
    {
        if (rep->use_count > 1)
        {
            String_rep*  new_rep = new String_rep(rep->data);
            rep->decrease();
            rep = new_rep;
            rep->increase();
        }
        char* ch = rep->data;
        while (*ch != '\0')
        {
            *ch -= 32;
            ++ch;
        }
    }
private:
    String_rep *rep;  //引用计数器
};
ostream& operator<<(ostream &out, const String&s)
{
    out << s.rep->data;
    return out;
}
void main()
{
    String s1("hello");
    String s2(s1);
    String s3;
    s3 = s2;
    cout << "s1=" << s1 << endl;
    cout << "s2=" << s2 << endl;
    cout << "s3=" << s3 << endl;

s2.to_upper();

cout << "-----------------------------------------------" << endl;
   
    cout << "s1=" << s1 << endl;
    cout << "s2=" << s2 << endl;
    cout << "s3=" << s3 << endl;
}

String类的写时拷贝的更多相关文章

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

    由于释放内存空间,开辟内存空间时花费时间,因此,在我们在不需要写,只是读的时候就可以不用新开辟内存空间,就用浅拷贝的方式创建对象,当我们需要写的时候才去新开辟内存空间.这种方法就是写时拷贝.这也是一种 ...

  2. 标准C++类std::string的内存共享和Copy-On-Write(写时拷贝)

    标准C++类std::string的内存共享,值得体会: 详见大牛:https://www.douban.com/group/topic/19621165/ 顾名思义,内存共享,就是两个乃至更多的对象 ...

  3. String 类的实现(2)引用计数与写时拷贝

    1.引用计数 我们知道在C++中动态开辟空间时是用字符new和delete的.其中使用new test[N]方式开辟空间时实际上是开辟了(N*sizeof(test)+4)字节的空间.如图示其中保存N ...

  4. String写时拷贝实现

    头文件部分 1 /* 版权信息:狼 文件名称:String.h 文件标识: 摘 要:对于上版本简易的String进行优化跟进. 改进 1.(将小块内存问题与大块分别对待)小内存块每个对象都有,当内存需 ...

  5. 计算机程序的思维逻辑 (73) - 并发容器 - 写时拷贝的List和Set

    本节以及接下来的几节,我们探讨Java并发包中的容器类.本节先介绍两个简单的类CopyOnWriteArrayList和CopyOnWriteArraySet,讨论它们的用法和实现原理.它们的用法比较 ...

  6. 并发容器之写时拷贝的 List 和 Set

    对于一个对象来说,我们为了保证它的并发性,通常会选择使用声明式加锁方式交由我们的 Java 虚拟机来完成自动的加锁和释放锁的操作,例如我们的 synchronized.也会选择使用显式锁机制来主动的控 ...

  7. Java编程的逻辑 (73) - 并发容器 - 写时拷贝的List和Set

    ​本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http: ...

  8. 写时拷贝(Copy On Write)方案详解

    本文旨在通过对 写时拷贝 的四个方案(Copy On Write)分析,让大家明白写时拷贝的实现及原理. 关于浅拷贝与深拷贝,我在之前的博客中已经阐述过了  浅拷贝容易出现指针悬挂的问题,深拷贝效率低 ...

  9. rust漫游 - 写时拷贝 Cow<'_, B>

    rust漫游 - 写时拷贝 Cow<'_, B> Cow 是一个写时复制功能的智能指针,在数据需要修改或者所有权发生变化时使用,多用于读多写少的场景. pub enum Cow<'a ...

随机推荐

  1. CSU 1802 小X的战斗力【拓扑dp】

    题目链接 题意:n个人,每个人有一个能力值.给出m组关系A, B, 表示A的能力值大于B的能力值. 问:m组关系中是否有自相矛盾的?若不矛盾,问:第1个人在所有人的能力值中排名第几?有多少人的能力值的 ...

  2. 这个算asp.net的一个bug吗?

    asp.net设置按钮Enabled="false"后OnClientClick中添加的验证脚本消失了 下面的确可以 <asp:Button ID="btnRegi ...

  3. linux 文件类型 文件权限

    linux中常见的文件类型有: “—”表示普通文件 :-rw-r--r-- 1 root root 41727 07-13 02:56 install.log   “d”表示目录 :drwxr-xr- ...

  4. 彻底理解ThreadLocal

    ThreadLocal是什么 早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路.使用这个工具类可以很简洁地 ...

  5. Java中去除StringBuffer最后一个字符

    原文:http://www.cnblogs.com/shaozhiheng/p/3661714.html 由于编写了这么一段代码: Iterator it3 = set.iterator(); whi ...

  6. myeclipse黑色主题怎么还原

    删除workspace-->.metadata-->.plugins-->org.eclipse.core.runtime

  7. TWaver HTML5 (2D)--基本概念

    基本概念 TWaver HTML5(以下简称TWaver)使用HTML5技术和javascript语言,可在支持HTML5的浏览器上进行绘图. 使用TWaver前,需熟悉几个基本概念:图元(Eleme ...

  8. 栅栏 CyclicBarrier

    java.util.concurrent.CyclicBarrier 类是一种同步机制,它能够对处理一些算法的线程实现同步.换句话讲,它就是一个所有线程必须等待的一个栅栏,直到所有线程都到达这里,然后 ...

  9. [redis] windwos下安装和使用redis

    一篇很好的入门学习文章:Redis学习 Redis是一种nosql数据库,在开发中常用做缓存. 1.下载地址: 低版本下载地址:https://github.com/dmajkic/redis/dow ...

  10. python3 安装scrapy Exception: Traceback (most recent call last): File "/usr/lib/python3/dist-packages/pip/req/req_install.py", line 1006, in check_if_exists解决方法

    错误代码: Exception: Traceback (most recent call last): File , in check_if_exists self.satisfied_by = pk ...