数据结构《19》----String容器的三种实现

本文探讨了String容器的三种实现方式,从简单到复杂,重点介绍了利用copy on write (COW)和reference counting技术来优化string操作。在COW技术的应用中,以Linux内核在进程fork时如何处理地址空间为例,说明了如何通过引用计数和写时复制提升效率。
摘要由CSDN通过智能技术生成

一、序言

一个简单的string 容器到底是如何实现的?

本文给出了 String 的三种从易到难的实现,涉及了 reference counting, copy on write 的技术。


二、第一个实现

我们设计的string类里面包含一个char* 的指针, 通过指针的管理,来实现string的基本功能。

废话不多说了,直接上代码:


class String
{
public:
  String(): str(new char[1]) {str[0] = '\0';}

  String(const char* s): str(new char[strlen(s)+1]) {
    strcpy(str, s);
  }

  //copy control
  String(const String& rhs): str(new char[strlen(rhs.str)+1]){
    strcpy(str, rhs.str);
  }

  String& operator=(String rhs);

  ~String(){
    delete [] str;
  }

  void swap(String &rhs) {
    std::swap(str, rhs.str);
  }

  //accesory
  size_t size() const {return strlen(str);}
  const char* c_str() const {return str;}

  bool operator==(const String &rhs) const{
    return strcmp(str, rhs.str) == 0 ? true : false;
  }

  bool operator<(const String &rhs) const {
    return strcmp(str, rhs.str) < 0 ? true : false;
  }

  char operator[](size_t i) const {
    return str[i];
  }

  char& operator[](size_t i){
    return str[i];
  }

  friend ostream& operator<<(ostream& out, const String &rhs) {
    out << rhs.str;
    return out;
  }

private:
  char *str;
};

/**
 * deal with self-assignment
 * refer to Effective C++
 */
String& String::operator=(String rhs) //yes, copy by value
{
  swap(rhs);
  return *this;
}


几点注意的:类包含指针,因此需要 copy control, 也就是自行实现拷贝构造函数,赋值构造函数,析构函数,
而不能依赖于编译器生成的默认版本,默认版本拷贝仅仅是 bitwise 拷贝,会导致悬挂指针等等问题。

二、改进版本

第一个版本过于简单,相比聪明的读者早已看 strlen 不顺眼,因此,下一个版本加入表示当前字符串长度的变量。
代码如下:


class String
{
  friend ostream& operator<<(ostream& out, const String &s){
    out << s.str;
    return out;
  }
public:
  String() :len(0), str(new char[1]) {
    str[0] = '\0';
  }

  String(const char *s) : len(strlen(s)), str(NULL){
    str = new char[len + 1];
    strcpy(str, s);
  }
  
  ~String() {
    delete [] str;
  }

  //copycontrol
  String(const String &rhs): len(rhs.len), str(new char[rhs.len+1])
  {
    strcpy(str, rhs.str);
  }

  String& operator=(String rhs){ //yes, copy by value
    swap(rhs);
    return *this;
  }

  void swap(String &rhs){
    std::swap(str, rhs.str);
    std::swap(len, rhs.len);
  }

  const char* c_str() const {
    return str;
  }

  size_t size() const{
    return len;
  }

  bool operator==(const String &rhs) const{
    return strcmp(str, rhs.str) == 0 ? true : false;
  }

  bool operator<(const String &rhs) const{
    return strcmp(str, rhs.str) < 0 ? true : false;
  }

  char operator[](size_t i) const{
    return str[i];
  }

  char& operator[](size_t i){
    return str[i];
  }

private:
  size_t len;
  char *str;
};


三、写时拷贝的 String
Copy-on-write(以下简称COW)是一种很重要的优化手段。它的核心思想是懒惰处理多个实体的资源请求,在多个实体之间共享某些资源,直到有实体需要对资源进行修改时,才真正为该实体分配私有的资源。

COW技术的一个经典应用在于Linux内核在进程fork时对进程地址空间的处理。由于fork产生的子进程需要一份和父进程内容相同但完全独立的地址空间,一种做法是将父进程的地址空间完全复制一份,另一种做法是将父进程地址空间中的页面标记为”共享的“(引用计数+1),使子进程与父进程共享地址空间,但当有一方需要对内存中某个页面进行修改时,重新分配一个新的页面(拷贝原内容),并使修改进程的虚拟地址重定向到新的页面上。



class String
{
  friend ostream& operator<<(ostream &out, const String &str){
    out << str.value->data;
    return out;
  }
public:
  String(const char *str = "\0")
    :value(new StringValue(str)) {}
  String(const String&);
  ~String();
  String& operator=(const String &rhs);

  char& operator[](size_t i);
  char operator[](size_t i) const; 
  size_t size() const {
    return strlen(value->data);
  }
private:
  void destroy() {
    if(--value->ref_count == 0)
      delete value;
  }
  struct StringValue
  {
    StringValue(const char* str)
      :data(new char[strlen(str)+1]), ref_count(1) {
      strcpy(data, str);
    }
    ~StringValue(){
      delete [] data;
    }

    size_t ref_count;
    char *data;
  };
  struct StringValue *value; 
};

String::String(const String& rhs)
{
  ++ rhs.value->ref_count;
  value = rhs.value;
}

String& String::operator=(const String& rhs)
{
  ++ rhs.value->ref_count;
  destroy();
  value = rhs.value;
  return *this;
}

String::~String()
{
  destroy();
}

char& String::operator[](size_t i) 
{
  //copy on write
  if(value->ref_count > 1)
  {
    -- value->ref_count; //do not forget
    value = new StringValue(value->data);
  }
  return value->data[i];
}

char String::operator[](size_t i) const
{
  return value->data[i];
}


四、参考
1. http://www.cnblogs.com/promise6522/archive/2012/03/22/2412686.html
2. More Effective C++


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值