删除文章

确定要删除这篇文章吗?

取消
确定

C++ String正确实现以及关键点

     阅读(435)  2018-05-10 00:17:21

正确实现String可以考察C++的一些基本功,稍不注意就会出错,下面来列举一下关键点:

  1. 构造函数,拷贝构造,赋值操作符是必须的;
  2. 成员初始化列表执行顺序;
  3. c_str()不要返回空指针;
  4. 实现swap函数;
  5. 分配内存的时候要用外面传进来的size;
  6. 赋值操作符的实现方法:参数以传值的形式;
  7. 析构函数delete [];

先看下代码:

class String {
public:
    String() 
        : len_(0)
        , buffer_(nullptr) 
    {
    }

    String(const char *str, size_t size)
        : len_(size)
        , buffer_(size ? new char[size + 1] : nullptr)
    {
        if (buffer_) {
            std::copy(str, str + len_, buffer_);
            buffer_[size] = '\0';
        }
    }

    String(const char *str)
        : String(str, strlen(str))
    {
    }

    String(const String &str)
        : String(str.buffer_, str.len_)
    {
    }

    ~String()
    {
        delete[] buffer_;
    }

    void swap(String& right) 
    {
        std::swap(len_, right.len_);
        std::swap(buffer_, right.buffer_);
    }

    // 传统写法
    //String& operator= (const String &str)
    //{
    //  String tmp(str);
    //  this->swap(tmp);
    //  return *this;
    //}

    String& operator=(String str)
    {
        this->swap(str);
        return *this;
    }

    size_t size()
    {
        return len_;
    }

    const char* c_str()
    {
        return buffer_ ? buffer_ : "";
    }

private:
    size_t len_;
    char *buffer_;
};

简化代码

第二个构造函数很重要,有了它后面的构造函数写起来就方便多了。否则你要写多个类似下面的代码:

    String(const char *str, size_t size)
        : len_(size)
        , buffer_(size ? new char[size + 1] : nullptr)
    {
        if (buffer_) {
            std::copy(str, str + len_, buffer_);
            buffer_[size] = '\0';
        }
    }

成员初始化列表

注意:成员初始化列表是以成员定义的顺序来进行初始化的。
如果成员变量定义的是如下顺序:

private:
  char *buffer_;
    size_t len_;

而构造函数是下面写法是会出错的:

  // 错误的写法
    String(const char *str, size_t size)
        : len_(size)
        , buffer_(len_ ? new char[len_ + 1] : nullptr)
    {
        if (buffer_) {
            std::copy(str, str + len_, buffer_);
            buffer_[size] = '\0';
        }
    }

根据len_的长度来创建buffer_,看起来先将size赋值给了len_然后再使用len_,但其实在初始化buffer_的时候len_还没有被初始化,所以导致buffer_一直为nullptr。为了避免这个错误你需要注意成员变量的初始化顺序,但是这样做并不好,当成员变量多了的时候很难注意到这个问题。所以最好的做法就是:在成员初始化列表中使用传进来的参数,不要使用赋值后的参数。

字符串以'\0'结尾

由于实现的是字符串所以要多分配一个字符已'\0'结尾,如果是其他buffer,如:int[]就不需要了。

参数通过传值的方式实现赋值操作符

    String& operator=(String str)
    {
        this->swap(str);
        return *this;
    }

原理是:str传进来的是一个临时拷贝,当swap之后,把当前this的buffer_交换给了临时str,临时str的buffer_赋值给了this,当临时str析构的时候它帮我们把this先前的buffer_给释放了,而它的buffer_给了this。

文章评论

Keep it simple,stupid
文章数
300
总访问量
443062
今日访问
951
最近评论

xuehaoyun : 很不错,来围观一下
tujiaw : 抱歉csdn code服务关闭了,这个代码我也找不到了
于淞 : 你好,这个文章的源码能分享一下吗,songsong9181@163.com,谢谢了 上面的写错了
于淞 : 你好,这个文章的源码能分享一下吗,838106303@163.com,谢谢了 上面的链接不能用了
tujiaw : 多谢多谢
essaypinglun college-paper.org : 很好的博客,赞赞
Folly : 这个实现有点奇怪,Qt为什么没有统一的比对方法。
过多s : alert("hello, world!")
tujiaw : 还不错哦
回到顶部