要写string的函数,首先就是创建一个string的类,在实现string类的过程中一直不断优化,以减少代码量和考虑不周的问题,首先我先给出刚开始的经典写法

经典解法(初级程序员适用)

class String

{

public:

String(const char *str = ""):       //构造函数

_str(new char[strlen(_str)+1])

{

strcpy(_str, str);

}

String(const String &str)         //拷贝构造函数

{

_str = new char[strlen(str._str) + 1];

strcpy(_str, str._str);

}

~String()                         //析构函数

{

if (_str != NULL)

{

delete[]_str;

}

}

public:

String &operator=(const String &str)//'='符号重载

{

if (this != &str)

{

delete[]_str;

_str = (char*)new char[strlen(str._str) + 1];

strcpy(_str, str._str);

}

return *this;

}

}

此写法看似解决了string类的定义问题,实则仔细查看此代码你会发现代码在开辟空间时并未检测开辟空间是否成功,若new开辟空间失败,_str的内容已经丢失,所以可以看出来好的代码必定是经过深思熟虑后写出来的,在写代码时一定要考虑各种边际情况和各种异常情况的处理,在我们发现上面的问题后作出修改,代码已不够简洁,进过优化后的代码如下:

class String

{

public:

String(char *str = ""):// 构造函数

_str(new char[strlen(str)+1])

{

strcpy(_str, str);

}

//使用swap,一致性

String(String &str) ://拷贝构造函数,注意必须给_str赋初值,否则_str是随机值,指向的是一块非法空间

_str(NULL)

{

String tmp(str._str);

swap(_str, tmp._str);

}

String &operator=(String str)// '='号重载,巧妙使用值传递,在函数结束时,调用析构函数,将_str之前的空间释放

{

swap(_str, str._str);

return *this;

}

~String()                         //析构函数

{

if (_str != NULL)

{

delete[]_str;

}

}

在上边的代码中,我们发现在使用swap后代码变得简洁,而且在'='符号重载时也不会出现丢失_str内容的情况,特别注意在拷贝构造中,一定要给_str赋初值,否则在代码块结束会出现释放非法空间的情况,因为在_str未赋初值的情况下是一个随机值,也就是_str指向一块非法空间。

此时的写法依然不是最好的写法,因为在程序运行的过程中使用动态开辟所占用的时间的比较多,所以此时就有写时拷贝的概念:

在维基百科中是这么定义的,写入时复制(Copy-on-write)是一个被使用在程式设计领域的最佳化策略。其基础的观念是,如果有多个呼叫者(callers)同时要求相同资源,他们会共同取得相同的指标指向相同的资源,直到某个呼叫者(caller)尝试修改资源时,系统才会真正复制一个副本(private copy)给该呼叫者,以避免被修改的资源被直接察觉到,这过程对其他的呼叫只都是通透的(transparently)。此作法主要的优点是如果呼叫者并没有修改该资源,就不会有副本(private copy)被建立。

简单的来说,就是在程序运行的过程中,如果多个对象同时要求相同的内容,则系统会给他们指定相同的空间,直至其中一个对象需要修改内容时才会真正给这个对象复制一个副本,从而提高程序的运行效率。

代码如下:

class String            //写时拷贝

{

public:

String(const char* str = ""):

_str(new char[strlen(str) + 1 + CAPACITY+4])     //多开辟四个字节存放空间使用次数

, _capacity(strlen(str) + 1 + CAPACITY)

, _size(strlen(str))

{

*(int *)_str = 1;

_str = _str + 4;

strcpy(_str, str);

}

String(const String &str)

:_str(str._str)

{

++*(PointFirst(_str));

_capacity = str._capacity;

_size = str._size;

}

~String()

{

if (--*PointFirst(_str) == 0)      //当使用相同空间的对象最后一次析构时,释放空间

{

delete[](_str - 4);

}

}

}
上面的代码和前面的不同处是在开辟空间时多开辟了四个字节去保存空间的使用次数,每次拷贝构造时加一,在析构时也是在保存的这个值为0时才会释放空间。

我们验证下写实拷贝和经典拷贝的效率差异

void Test()

{

String str("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");

int i = 0;

time_t start = time(NULL);

for (; i < 20000000; i++)

{

String stri(str);

}

time_t end = time(NULL);

cout << (end - start) << endl;

}//使用普通拷贝构造函数,用时25s,使用写实拷贝只需要3s,效率一目了然。

在下面我再将自己写的一些使用写实拷贝的一些简单的string函数贴出来:
代码如下:

public:

String &operator=(const String &str)

{

if (this != &str)

{

if (--(*PointFirst(_str)) == 0)     //当此对象独立使用一块空间时,在赋值前释放这块空间

{

delete[]PointFirst(_str);

}

_str = str._str;

++*PointFirst(str._str);

}

return *this;

}

char &operator[](int index)

{

if ((*PointFirst(_str)-1) == 0)

{

return _str[index];

}

--*PointFirst(_str);

StringCopyWrite();

return _str[index];

}

public:

int Strcmp(const String &str)

{

char *pstr1 = _str;

char *pstr2 = str._str;

while (*pstr1 == *pstr2)

{

pstr1++;

pstr2++;

if (*pstr1 == '\0'&&*pstr2 == '\0')

{

return 0;

}

}

if (*pstr1 > *pstr2)

{

return 1;

}

return -1;

}

bool operator==(const String &str)

{

if (Strcmp(str) == 0)

{

return true;

}

return false;

}

bool operator>(const String &str)

{

if (Strcmp(str) == 1)

{

return true;

}

return false;

}

bool operator<(const String &str)

{

if (Strcmp(str) == -1)

{

return true;

}

return false;

}

//写时拷贝函数

void insert(int pos, char ch)

{

if (--*PointFirst(_str) != 0)  //和其他类成员变量公用一块空间

{

StringCopyWrite();

}

CheckCapacity(Strlen(_str) + 2);

int index = _size;

int sz = Strlen(_str);

while (sz >= pos)

{

_str[index - 1] = _str[sz];

index--;

sz--;

}

_str[pos] = ch;

}

void insert(int pos, char *str)

{

if (--*PointFirst(_str) != 0)

{

StringCopyWrite();

}

CheckCapacity(Strlen(_str) + Strlen(str) + 1);

int sz = Strlen(_str);

int index = _size;

while (sz >= pos)

{

_str[index - 1] = _str[sz];

index--;

sz--;

}

while (*str != '\0')

{

_str[pos++] = *str++;

}

}

void insert(int pos, const String &str)

{

if (--*PointFirst(_str) != 0)

{

StringCopyWrite();

}

this->insert(pos, str._str);

}

void PushBack(char ch)

{

if (--*PointFirst(_str) != 0)

{

StringCopyWrite();

}

int sz = size();

this->insert(sz - 1, ch);

}

int size()//返回值即为字符串长度(包含'\0')

{

char *p = _str;

int size = 0;

while (*p != '\0')

{

size++;

p++;

}

return ++size;

}

void CheckCapacity(int sz)

{

if (sz >= _capacity)

{

_capacity = sz + CAPACITY;

}

_size = sz;

char *tmp = new char[_capacity + 4];

*(int *)tmp = *PointFirst(_str);

tmp += 4;

Strcpy(tmp, _str);

swap(tmp, _str);

delete[]PointFirst(tmp);

}

void StringCopyWrite()

{

char *tmp = _str;

_str = new char[Strlen(_str) + 5];

_str += 4;

Strcpy(_str, tmp);

*PointFirst(_str) = 1;

}

private:

char *_str;

int _size;

int _capacity;

};

在使用动态开辟的程序中,非常容易造成内存泄漏,很多程序的问题都处在释放动态内存处,这也是c++中比较难的一个知识点,只有能熟练使用动态内存开辟,才能将c++的魅力体现出来。

随后再更........

转载于:https://blog.51cto.com/10810196/1749747

关于string的一些心得体会相关推荐

  1. 对c语言课程的心得体会,C语言课程设计心得体会

    C语言课程设计心得体会 回想这三周C语言课程设计的过程,真是痛并快乐着. 从领到书的那一刻,我就很郁闷?<C语言程序设计>到底事学什么的,到底有什么用.刚开始上课时?还在迷茫这门课程是用来 ...

  2. ngrx心得体会总结

    ngrx心得体会总结 一个典型的场景:添加店铺商品,其中店铺有多个,每个店铺有不同的商品分类,商品分类可以多级! @Injectable() export class AppEffects {// 添 ...

  3. 中国象棋程序的设计与实现(七)--心得体会和开发日志

    上大学那会,还没有自己专属的SVN仓库,但是我已经意识到了管理代码的重要性,我最常用的一种需求就是恢复到上一个正确的版本. 为此,我每实现一个重要功能,就会备份整个项目一次,增加开发日志,如" ...

  4. 武汉群硕面试心得体会(上)

    关于简历: 简历模版来自网上下载(基本信息的格式,省去了部分排版时间),专业技能.项目经验等大部分内容都是自己写的,写完后给余博学长看了一下,借鉴了自我评价部分的内容,没有使用我自己写的自我评价,另外 ...

  5. 做python的心得体会_实训python的心得体会

    如何学习Python的一些总结 C++.Java乃至C#都可以看做是同一类型的语言:C++还算灵活,但纷繁复杂的语法使得生产效率低下,Java提高了生产效率,却损失了灵活性;C#算是在生产效率和灵活性 ...

  6. python程序设计心得体会感想-如何快速学会Python

    如何快速学会Python 发布时间:2020-02-04 一.什么是Python Python是一种计算机程序设计语言.是一种面向对象的动态类型语言,最初被设计用于编写自动化脚本(shell),随着版 ...

  7. java类与对象实验报告心得体会_java上机实验心得体会报告(大全五篇)

    北京联合大学信息学院 "面向对象程序设计"课程上机实验报告 题目: JAVA上机实验心得体会 姓名(学号): 专业:计算机科学与技术 编制时间: 2012年12月19日 版本: 1 ...

  8. java实验2总结心得,java实验的心得体会

    java实验的心得体会 java实验心得体会篇一:java实验总结 1. 设计一个Person类,包含:姓名,年龄,性别.要求:该类至多只能创建一男.一女两个对象! 2. 设计一个测试类Test,创建 ...

  9. java实验2总结心得,打字小游戏JAVA实验总结及心得体会

    篇一:扫雷游戏实验报告 课程设计 班 级: 姓 名: 学 号: 指导教师: 成 绩: 电子与信息工程学院信息与通信工程系 目录 1.任务概述------------------------------ ...

最新文章

  1. 太有缘!和同专业师兄同名同姓同年同月同日生还是同导师是什么体验?
  2. Hibernate关系映射 一对一双向外键关联@OneToOne Annotation方式
  3. ueditor1.4.3jsp版成功上传图片后却回显不出来与在线管理显示不出图片的解决方案...
  4. Java多线程编程的常见陷阱
  5. java学习-http中get请求的非ascii参数如何编码解码探讨
  6. ASP保存远程图片到本地 同时取得第一张图片
  7. python scale()函数_【Python菜鸟进阶大神】Matplotlib数据可视化007:词云
  8. P4847 银河英雄传说V2 非旋treap
  9. 如何在oracle中查询所有用户表的表名、主键名称、索引、外键等
  10. 第七十一期:管理 | 技术Leader:选OKR还是KPI?
  11. c如何通过偏移量取出文件中的字节_理一理C语言字节对齐的那些事
  12. Android 6.0 动态权限申请注意事项
  13. 2021-03-23梦笔记
  14. Tensorflow分布式机器学习平台
  15. 摄影测量之空间后方交会程序
  16. 改进初学者的PID-测量的比例编码
  17. HDFS遍历子目录 Hadoop fs -ls -R path
  18. 妹子图 Spider
  19. SIM7600CE TCP AT指令
  20. 实例图解:摄影构图大实话

热门文章

  1. Java连接Oracle数据库示例
  2. Android Studio连接天天模拟器
  3. Linux多线程编程四(条件变量)
  4. 软考中项学习之路--在路上
  5. Struts2中action获取request、response、session的方式
  6. Serendipity解决IE缓存为0
  7. [转帖]ASP.NET中常用的优化性能的方法
  8. 10.25T2 二维线段树
  9. 一个自定义python分布式爬虫框架。
  10. mysql 开发进阶篇系列 10 锁问题 (使用“索引或间隙锁”的锁冲突)