存量客户 uitableview mongoose jar angular material stl background Egret Engine vue添加class jquery绑定change事件 webform开发教程 oracle存储过程返回值 python3网络编程 python创建文件 java连接mysql java时间 java抽象 java运行环境配置 java文件流 javafloat java集合遍历 java面向对象 java异常处理 java游戏开发教程 灼热峡谷 俄罗斯方块java代码 comsol软件下载 电子书制作软件 电子商城系统 js发送http请求 js代码混淆工具 一键换肤大师 ajaxpro 目标聚光灯 梦想世界科举答案 ps光照效果 a1474 谷歌地球怎么用不了 换肤助手 ps怎么去痘痘
当前位置: 首页 > 学习教程  > 编程学习

【C++】深浅拷贝实现String类

2021/1/9 2:04:52 文章标签: 深浅拷贝

什么是深浅拷贝? 定义字符串char* str1"hello"; 现在定义一个字符串char* str2和str1的数据相同,这种情况分两种; str1和str2数据和空间都相同,即str2指向str1 的地址空间。str2另开辟空间,再将str1的数据拷贝给str…

什么是深浅拷贝?

定义字符串char* str1="hello";

现在定义一个字符串char* str2和str1的数据相同,这种情况分两种;

  1. str1和str2数据和空间都相同,即str2指向str1 的地址空间。
  2. str2另开辟空间,再将str1的数据拷贝给str2,即str1和str2数据相同,指向的地址不同。

第一种情况叫做浅拷贝,第二种情况叫做深拷贝

而在C++中,使用浅拷贝容易发生很严重的代码事故---内存泄漏

str1和str2指向同一段地址空间,而析构函数是系统自动生成并调用,会产生一段空闲析构两次的情况。

下面使用深浅拷贝的传统写法和现代写法实现String类:

传统写法和现代写法主要区别在于拷贝构造函数和赋值操作符重载函数里写法不同,如下;

拷贝构造函数的不同写法:

 void Swap(String& s)
    {
      swap(_str,s._str);
      swap(_size,s._size);
      swap(_capacity,s._capacity);
    }
    //传统写法 
     String(const String& s)
         :_str(new char[strlen(s._str)+1])
       {
         strcpy(_str,s._str);
       }
    //现代写法
    String(const String& s)
      :_str(NULL)
    {
      String tmp(s._str);
      Swap(tmp);
    }

赋值运算符重载函数的不同写法:

 现代写法
    String& operator=(const String& s){
      if(this!=&s){
        String tmp(s._str);
        swap(_str,tmp._str);
      }
      return *this;
    }
    最好的现代写法
    String& operator=(String s){
      if(this!=&s){
        Swap(s);
        return *this;
      }
    }
    //传统写法
    //s1=s2,s2的长度可能超过s1的空间
    //如果只是值拷贝,同一个空间会析构两次,导致内存泄漏
    //要先释放空间
        String& operator=(const String& s)
        {
          if(this!=&s){
            delete[] _str;
            char* tmp=new char[strlen(s._str)+1];
            strcpy(tmp,s._str);
            _str=tmp;
          }
          return *this;
        }

全部代码实现:

#pragma once
#include<iostream>
#include<string.h>
#include<assert.h>
using namespace std;
//1.传统写法 
//2.现代写法 拷贝构造和赋值有新的写法
class String{
  public:
    String(const char* str)
      :_size(strlen(str))
       ,_capacity(_size)
  {
    _str=new char[_size+1];
    strcpy(_str,str);
  }
    void Swap(String& s)
    {
      swap(_str,s._str);
      swap(_size,s._size);
      swap(_capacity,s._capacity);
    }

    //s1(s);深拷贝
        String(const String& s)
         :_str(new char[strlen(s._str)+1])
       {
         strcpy(_str,s._str);
       }
    //现代写法
  /*  String(const String& s)
      :_str(NULL)
    {
      String tmp(s._str);
      Swap(tmp);
    }
    现代写法
    String& operator=(const String& s){
      if(this!=&s){
        String tmp(s._str);
        swap(_str,tmp._str);
      }
      return *this;
    }*/
    最好的现代写法
    String& operator=(String s){
      if(this!=&s){
        Swap(s);
        return *this;
      }
    }
    //s1=s2,s2的长度可能超过s1的空间
    //如果只是值拷贝,同一个空间会析构两次,导致内存泄漏
    //要先释放空间
        /*String& operator=(const String& s)
        {
          if(this!=&s){
            delete[] _str;
            char* tmp=new char[strlen(s._str)+1];
            strcpy(tmp,s._str);
            _str=tmp;
          }
          return *this;
        }
*/
    ~String(){
      if(_str){
        delete[] _str;
        _str=NULL;
      }
    }
    void Expand(size_t n){
      if(n>_capacity){
        char* tmp=new char[n+1];
        strcpy(tmp,_str);
        delete[] _str;
        _str=tmp;
        _capacity=n;
      }
    }
    void PushBack(char ch){
      if(_size>=_capacity){
        Expand(2*_size); 
      }
      _str[_size]=ch;
      _str[_size+1]='\0';
      ++_size;
    }
    void Append(const char* str){//插入字符串
      size_t len=strlen(str);
      if(_size+len>=_capacity){
        Expand(_size+len);
      }
      strcpy(_str+_size,str);
      _size+=len;
    }
    void PopBack()
    {
      assert(_size);
      _str[_size--]='\0';
      --_size;
    }
    void Insert(size_t pos,char ch){
      assert(pos<=_size);
      if(_capacity==_size){
        Expand(2*_capacity);
      }
      size_t end=_size;
      while(end>=pos){
        _str[end+1]=_str[end];
        --end;
      }
      _str[pos]=ch;
      ++_size;
    }
    void Insert(size_t pos,const char* str){
      assert(pos<=_size);
      int len=strlen(str);
      if(_size+len>_capacity){
        Expand(_size+len);
      }
      for(int i=pos;i<_size;i++){
        _str[i+len]=_str[i];
      }
      for(int j=0;j<len;j++){
        _str[j+pos]=str[j];
      }
    }
    void Erase(size_t pos,size_t n)
    {
      assert(pos<=_size);
      if(pos==_size){
        _str[_size-1]='\0';
        --_size;
      }else{
        strcpy(_str+pos,_str+pos+n);
      }
    }
    size_t Size()
    {
      return _size;
    }
    size_t Capacity()
    {
      return _capacity;
    }
    bool Empty()
    {
      return _size==0;
    }
    char& operator[](size_t pos){//读取某个位置的字符
      return _str[pos];
    }
    size_t Find(char ch)
    {
      size_t count=0;
      for(int i=0;i<_size;i++){
        if(_str[i]==ch){
          return count;
        }
        count++;
      }
    }
    size_t Find(const char* str)
    {
      size_t count=0;
      char* src=_str;
      while(*src){
        const char* dest=str;
        while(*dest==*src){
          dest++;
          src++;
        }
        if(*dest=='\0'){
          return count;
        }
        src++;
        count++;
      }
      return size_t(-1);
    }

    String operator+(char ch)
    {
      String tmp(*this);
      tmp.PushBack(ch);
      return tmp;
    }
    String& operator+=(char ch){
      this->PushBack(ch);
      return *this;
    }
    //s1+=s2
    String operator+=(const String& str){
      *this+=str._str;//s._str是字符串,会去调用上面的operator+= 
      return *this;
    }
    String operator+(const char* str){
      assert(str);
      String tmp(*this);
      tmp.Append(str);
      return tmp;
    }
    String& operator+=(char* str){
      this->Append(str);
      return *this;
    }
    int _strcmp(const char* str1,const char* str2){
      while(*str1&&*str2){
        if(*str1>*str2){
          return 1;
        }else if(*str1<*str2){
          return -1;
        }else{
          str1++;
          str2++;
        }
      }
      return 0;
    }
    //s1<s2 
    bool operator<(const String& s){
      if((_strcmp(_str,s._str))==-1){
        return true;
      }else{
        return false;
      }
    }
    bool operator<=(const String& s)
    {
      if((_strcmp(_str,s._str))<=0){
        return true;
      }else{
        return false;
      }
    }
    bool operator>(const String& s)
    {
      if((_strcmp(_str,s._str))>0){
        return true;
      }else{
        return false;
      }
    }
      bool operator>=(const String& s)
      {
        if((_strcmp(_str,s._str))>=0){
          return true;
        }else{
          return false;
        }
      }

    //返回C形式字符串
    char* c_str(){
      return _str;
    }
  private:
    char* _str;
    size_t _size;
    size_t _capacity;
};
void TestString(){
  String s1("hello");
 // cout<<s1.c_str()<<endl;
//  s1.Insert(3,"花花");
//  cout<<s1.c_str()<<endl;
//  cout<<s1.Empty()<<endl;
//    cout<<s1.Find("ol")<<endl;
}
int main(){
  TestString();
}

 


本文链接: http://www.dtmao.cc/news_show_1100287.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?