• 实现一个string类


    需要实现的基本功能:构造函数、拷贝构造函数、赋值函数、析构函数. (以前合称big three, 现在叫做copy control)

      

     1 class String {
     2 public:
     3     String(const char* str = "");
     4     String(const String& rhs);
     5     ~String();
     6     String& operator=(const String& rhs);
     7     size_t size const();
     8     const char* c_str const();
     9 private:
    10     char* data;
    11 };
    12 
    13 /* 不简洁版本
    14 String::String(const char* str) {
    15     if (str == NULL) {
    16         data = new char[1];
    17         *data = '';
    18     } else {
    19         int len = strlen(str);
    20         data = new char[len + 1];
    21         strcpy(data, str);
    22     }
    23 }
    24 */
    25 
    26 String::String(const char* str) {
    27     data = new char[strlen(str) + 1];
    28     strcpy(data, str);
    29 }
    30 
    31 String::~String() {
    32     delete[] data;
    33 }
    34 
    35 String::String(const String& rhs) {
    36     data = new char[rhs.size() + 1];
    37     strcpy(data, rhs.c_str());
    38 }
    39 
    40 // bad version
    41 String& String::operator=(const String& rhs) {
    42     if (this != &rhs) {
    43         delete[] data;
    44         data = new char[rhs.size() + 1];
    45         strcpy(data, rhs.c_str());
    46     }
    47     return *this;
    48 }
    49 
    50 size_t String::size() const{
    51     return strlen(data);
    52 }
    53 
    54 const char* String::c_str const() {
    55     return data;
    56 }

     改进版:【详情参考ref4、剑指offer第一题】

    上面的拷贝构造函数有个潜在隐患:String类涉及到内存分配操作,这个new操作可能会抛出异常。

    解决方法:

    可以通过”copy and swap“的策略来实现。其原理很简单:即先对打算修改的对象做出一个副本(copy),在副本上做必要的修改。如果生成副本时出现任何异常,原对象依然能保证不变。如果修改成功,则通过不抛出任何异常的swap函数将副本和原对象进行交换(swap)。[ ref ]

    1 String& String::operator=(const String &rhs) {
    2     String tmp(rhs);
    3     swap(data, tmp.data);
    4     return *this;
    5 }

    如果把参数中的引用传递换成值传递,那就相当于自动创建出一个临时对象来。如下是另一种等价形式。

    1 String& String::operator=(String rhs) {
    2     swap(data, rhs.data);
    3     return *this;
    4 }

    在swap之后,相当于两指针指向的内存区域进行了互换。当退出函数时,tmp生命周期已到,将被销毁,但是它销毁时释放的是交换后的内存区域,即原来的data所指的内存区域;它本来指向的内存区域现在归data管了,不会被释放。

    ref2和ref5都考虑了异常安全的问题。

    ref:

    1. 《高质量C/C++程序设计指南》附录A,B (可能有错误)

    2. http://coolshell.cn/articles/10478.html

    3. http://noalgo.info/382.html

    4. http://blog.csdn.net/worldwindjp/article/details/12967443

    5. http://guochunyang.me/2014/10/17/c++-11-zhiyouzhi-yinyong--san---shiyong-c++-11-bianxie-string-lei-yiji--yichang-anquan--de--yunsuanfu/

  • 相关阅读:
    C#下如何用NPlot绘制期货股票K线图(3):设计要显示的股票价格图表窗口并定义相应类的成员及函数
    C#下如何用NPlot绘制期货股票K线图(2):读取数据文件让K线图自动更新
    C#下如何用NPlot绘制期货股票K线图(1)?
    freemarker 常见问题
    关于Bootstrap table的回调onLoadSuccess()和onPostBody()使用小结
    mybatis 联表查询
    用mysql存储过程代替递归查询
    MYSQL 级联 添加外键
    IntelliJ Idea 常用快捷键列表
    MySQL大数据量分页查询方法及其优化
  • 原文地址:https://www.cnblogs.com/forcheryl/p/4699468.html
Copyright © 2020-2023  润新知