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(); }