String C++完整实现。

String C++实现

改进:

/*
版权信息:狼
文件名称:String.h
文件标识:
摘    要:对于上版本简易的String进行优化跟进。
  改进
  1.(将小块内存问题与大块分别对待)小内存块每个对象都有,当内存需求大于定义大小时利用动态分配
  2.实现大块内存的写时拷贝功能,提高效率,优化空间利用
  3.类似new[]实现机制:将动态内存块大小信息保存为隐藏“头”
  4.对于大块内存采取动态增长型。不够时扩容为当前大小的2倍
 
当前版本:1.2
修 改 者:狼
完成日期:2015-12-12
 
取代版本:1.1
原 作 者:狼
完成日期:2015-12-11
*/
#ifndef _STRING_H
#define _STRING_H
#include<iostream>
using namespace ::std;
 
namespace COW
{
 class String
 {
 friend  void Check_Interface(String &S);
 friend ostream& operator << (ostream&os, String &Str);

 public:
  String(const char* str = "");
  String(String& Str);
  String& operator=(const String& Str);
  ~String();
 
 public:
  int Find(char ch)const;
  int Find(const char* str)const;
  void PushBack(char ch);
  void Insert(size_t pos, char ch);
  void Insert(size_t pos, const char* str);
  bool Erase(size_t pos);
  bool Erase(size_t pos, size_t n);
  size_t Strlen()const;
 
 private:
  void InitInfo(size_t inUse); //初始化capacity and inUse
  void CheckMem(size_t add = 1); //对于内存操作时的增否处理
  const char* GetAdd()const; //获取当前字符串所在位置
  size_t capacity()const;  //读取头,获得有效容量长度
  int inCount()const;  //获取引用计数
  void decrease();//减少引用计数。
  void increase();//增加引用计数。
 
 private:
  enum{BufSize = 16};  //利用枚举进行数组初始化
  char *_str;    //内容块,“头”代替capacity
  char _buff[BufSize]; // 小内存块处理。
 };
 ostream& operator << (ostream&os, String &Str);
}
#endif
 
#include"String.h"
#pragma warning (disable:4351 4996)
 
using namespace COW;
 
String::String(const char *Str)
 :_str(NULL)
 , _buff()
{
 //采用动态分配
 if (strlen(Str) >= BufSize)
 {
  //1.记录引用计数,2.记录当前有效大小   strlen()+1
  _str = new char[strlen(Str) + 5+4];
  
  InitInfo(strlen(Str)+1);
 
  char *cur = const_cast<char*>(GetAdd());
  strcpy(cur, Str); //有效位置
 }
 else//静态存储
 {
  strcpy(_buff, Str);
 }
}
String::String(String& Str)
 :_str(NULL)
 , _buff()
{
 // 1.如果是小块内存。浅拷贝
 if (Str._str == NULL)
 {
  strcpy(_buff,Str._buff);
 }
 else
 {
  _str = Str._str;
  this->increase();
 }
}
String& String::operator=(const String& Str)
{
 //都是动态 且指向一处
 if (_str == Str._str&&_str != NULL)
  return *this;
 
 //两个都是小内存时
 if (Str._str == NULL&&_str==NULL)
 {
  strcpy(_buff, Str._buff);
 }
 //如果*this 是小内存(不存在内存变更,不用处理buff),Str 动态。
 else if (_str==NULL&&Str._str!=NULL)
 {
  _str = Str._str;
  this->increase();
 }
  
 //*this 动态,Str小内存。减少*this._str计数。。.更改buff
 else if(_str!=NULL&&Str._str==NULL)
 {
  this->decrease();
  _str = NULL;
  strcpy(_buff,Str._buff);
 }
 
 //两个都是动态分配 但不同
 else
 {
  this->decrease();
  _str = Str._str;
  this->increase();
 }
 return *this;
}
///////问题1...命名空间冲突时
ostream& COW::operator << (ostream&os, String &Str)
{
 if (Str._str)
 {
  os << (Str._str + 8);
 }
 else
  os << Str._buff;
 return os;
}
 

////////////////////////core_func
inline void String::increase()
{
 *(int*)_str += 1;
}
 
inline void String::decrease()
{
 if (_str != NULL)
 {
 
  //////问题2,,每次decrease之后必须变更_str..为NULL或者指向新块
  if ((*(int*)_str) - 1 != 0)
  {
   (*(int*)_str) -= 1;
  }
  else
  {
   delete[]_str;
   _str = NULL;
  }
 }
}
String::~String()
{
 this->decrease();
 _str = NULL;
}
 
///获取字符串的核心地址
const char *String::GetAdd()const
{
 //忘记给对正确起始点
 return _str ? _str+8 : _buff;
}
 
size_t String::capacity()const
{
 return *((int*)_str+1);
}
int String::inCount()const 
{
 return *((int*)_str);
}
 
//设置头 信息
void String::InitInfo(size_t inUse)
{
 *((int*)_str) = 1;
 *((int*)_str + 1) = inUse;
}
 
void String::CheckMem(size_t add)
{
 if (_str == NULL)
 {
  //小内存,且变动后不越界。
  if (strlen(_buff) + add < 16)
   return;
  //小内存,变动后越界
  else
  {
   _str = new char[strlen(_buff) + add + 9];
 
   InitInfo(strlen(_buff) + add+1);
  }
 }
 else
 {
  //容量足够,且引用计数为1;
  if (strlen(_str + 8) + add < capacity()&& inCount()==1)
  {
   //,但是写时拷贝,需要更新空间,所以顺带增加宽度
   //if (inCount() != 1)
   //{
   // int new_mem = (strlen(_str + 8) + add) * 2 + 9;
   // this->decrease();
   // 
   // _str = new char[new_mem];
   // //少了+1  会造成后续始终有一个字节浪费问题
   // InitInfo((strlen(_str + 8) + add) * 2 + 1);
   //}
   return;
  }
  else
  {
   //扩容后,容量为当前串长的2倍。  匹配使用,,用realloc 会出现问题
   //realloc(_str, (strlen(_str+8) + add) * 2 + 8);
  
   //不能delete,,写时拷贝忘记了。。引用计数问题忘记了?
   //delete[] _str;、
   //先计算所需,再decrease(),因为可能赋值为NULL,不得求Strlen
   int new_mem = (strlen(_str + 8) + add) * 2 + 9;
   this->decrease();
   _str = new char[new_mem];
   
   //少了+1  会造成后续始终有一个字节浪费问题
   InitInfo(new_mem-8);
  }
 } 
}
 
//////////////////publicFunc
int String::Find(char ch)const
{
 char *cur = const_cast<char*>(GetAdd());
 int pos = -1;
 while (*cur)
 {
  pos++;
  if (*cur == ch)
   return pos;
  cur++;
 }
 return -1;
}
 
int String::Find(const char* str)const
{
 if (str == NULL)
  return -1;
 char *cur = const_cast<char*>(GetAdd());
 int pos = -1;
 int len = strlen(str);
 while (*(cur + len))
 {
  pos++;
  ///简直,,if 后边有个;bug
  if (strncmp(cur, str, len) == 0)
   return pos;
  cur++;
 }
 return -1;
}
void String::PushBack(char ch)
{
 //首先保存内容。然后判断空间,然后存储。
 char p[100];
 char *st = const_cast<char*>(GetAdd());
 
 strcpy(p, st);
 
 CheckMem(); //默认为1;
 
 st = const_cast<char*>(GetAdd());
 strcpy(st, p);
 
 st[strlen(st)+1] = '\0';
 st[strlen(st)] = ch;
 
}
 
size_t String::Strlen()const
{
 return strlen(GetAdd());
}
 
void String::Insert(size_t pos, char ch)
{
 //越界有效化。。。
 if (pos >= Strlen())
 {
  pos = Strlen()-1;
 }
 //首先保存内容。然后判断空间,然后存储。
 char p[100];
 char *st = const_cast<char*>(GetAdd());
 
 strcpy(p, st);
 
 CheckMem(); //默认为1;
 
 st = const_cast<char*>(GetAdd());
 strncpy(st, p, pos);
 
 st[pos] = ch;
 
 //不能用strcat,前边字符串不存在'\0'
 strcpy(st + pos + 1, p + pos);
}
 
void String::Insert(size_t pos, const char* str)
{
 //越界有效化。。。
 if (pos >= Strlen())
 {
  pos = Strlen();
 }
 //首先保存内容。然后判断空间,然后存储。
 char p[100];
 char *st = const_cast<char*>(GetAdd());
 
 strcpy(p, st);
 
 int len = strlen(str);
 CheckMem(len); //默认为1;
 
 st = const_cast<char*>(GetAdd());
 strncpy(st, p, pos);
 
 strcpy(st + pos, str);
 
 strcpy(st + pos + len, p + pos);
}
 
bool String::Erase(size_t pos)
{
 char *cur = const_cast<char*>(GetAdd());
 size_t len = Strlen();
 if (pos >= len)
  return false;
 memmove(cur+ pos, cur + pos + 1, len + 1);
 return true;
}
 
bool String::Erase(size_t pos, size_t n)
{
 char *cur = const_cast<char*>(GetAdd());
 size_t len = strlen(cur + pos + 1);
 if (pos >= len)
  return false;
 memmove(cur + pos, cur + pos + n, len + 1);
 return true;
}
 
//////friend 友员函数不能跨越命名空间访问私有成员????????????
void Check_Interface(COW::String &S)
{
 //char  COW::String::*ch = S._str;
 //const char *ch = S._str;
 cout << endl;
}
 
///////////////////////////Test
#include"String.h"
using namespace COW;
 
void Test_COPY_EPU()
{
 
 String S1("hellow     world!");
 String S2("hellow world");
 String S3;
 S3 = S2;
 String S4;
 S4 = S1;
 //少对多,少对少
 cout << "小内存赋值" << S3 << endl;
 cout << "小内存赋值" << S4 << endl;
 
 //多对多,多对少
 String S5("change             world");
 S5 = S1;
 cout << S5 << endl;
 S5 = S2;
 cout << S5 << endl;
 //多多且等
 String S6 = S1;
 S6 = S1;
 cout << S6 << endl;
}
void Test_Find_Erase()
{
 String S1("hellow     world!");
 String S2("hellow world");
 cout << S1.Find('l') << endl;
 cout << S2.Find('z') << endl;
 cout << S1.Find("low") << endl;
 char*p = NULL;
 cout << S2.Find(p) << endl;
 
 S2.Erase(4);
 S2.Erase(4, 3);
 cout << S2 << endl;
}
 
void Test_Push_Insert()
{
 String S1("hellow     world!");
 String S2("hellow   world");
 //S1.PushBack('l');
 //S1.PushBack('v');
 //S2.PushBack('l');
 //S2.PushBack('v');
 int pos = S1.Find('l');
 S1.Insert(pos,'v');
 S1.Insert(100, "lv");
 cout << S1 << endl;
 cout << S2 << endl;
 
}
void main()
{
 //Test_COPY_EPU();
 //Test_Find_Erase();
 Test_Push_Insert();
}

 

posted @ 2015-12-12 11:22  狼行博客园  阅读(1578)  评论(0编辑  收藏  举报