之前做数据结构课设的时候写了一个string类,当时是为了达到工作量的要求,没怎么深入了解string类,稀里糊涂就写了出来,今天拿出来看了下发现写的好懒,于是今天修改了一下,拿出来凉一凉。。。
头文件如下:
#ifndef STRING_H
#define STRING_H
#include <iostream>
/*
分配在堆中的每一块内存都同时分配一个引用计数每次释放内存时检查引用计数,
若当前是指向内存的最后一个对象,则释放内存,释放引用计数若不是最后一个
对象,则让引用计数减一
*/
class String
{
public:
String();//默认构造
String(const char* cstr);//c风格的字符串构造
String(const String &str);//拷贝构造
~String();
bool insert(unsigned int pos, char args);//在pos之前插入字符
bool erase(unsigned int pos);//删除pos位置字符
bool assign(unsigned int pos, char c);//替换pos位置字符
bool append(const String &str);//追加字符串
unsigned int compare(const String &str);//字符串比较,返回第几个字符开始不一样
unsigned int findc(char c);//返回字符c第一次出现的位置
unsigned int rfindc(char c);//返回字符c最后一次出现的位置
unsigned int finds(const String &str);//匹配字符串第一次出现的位置
const char* c_str()
{
return this->data;
}
unsigned int size()//返回字符串中字符的个数
{
return this->_Length;
};
char& operator[](unsigned int pos);//下标访问
String operator+(const String &str);
const String& operator+=(const String &str);//字符串追加
const String& operator+=(const char* cstr);//字符串追加
const String& operator=(const String &str);//字符串赋值
const String& operator=(const char* cstr);//字符串赋值
bool operator==(const String &str);
bool operator==(const char* cstr);
bool operator!=(const String &str);
bool operator<(const String &str);
bool operator<=(const String &str);
bool operator>(const String &str);
bool operator>=(const String &str);
friend std::ostream& operator<<(std::ostream &os, String &str);//输出字符串
friend std::istream& operator>>(std::istream &is, String &str);//输入字符串
private:
int *reference_count = nullptr;//引用计数
unsigned int _Size = 15;//分配内存的单元大小,每次重新分配内存,内存空间大小都变成原来的3/2
char* data = nullptr;//指向字符串的指针
unsigned int _Length = 0;//字符串长度
void _AllocateMem()//重新分配内存并增大内存
{
char* p = new char[(this->_Size*3/2)];
strcpy(p, this->data);//拷贝字符串
if (*this->reference_count == 1)//若是最后一个则释放该内存
{
delete[] this->data;//释放内存
delete this->reference_count;//释放引用计数
}
else//否则就让引用计数减一
{
*this->reference_count = *this->reference_count - 1;
}
this->data = p;
this->_Size = this->_Size * 3 / 2;
this->reference_count = new int(1);
}
};
#endif
实现文件如下:
#include "String.h"
String::String()//default constructor
{
this->data = new char[this->_Size];//开辟内存
this->reference_count = new int(1);//引用计数
this->_Length = 0;
this->data[_Length] = '\0';
}
String::String(const char* cstr):String()//委托构造
{
while (*cstr!='\0')
{
if (this->_Length +1== this->_Size)//若空间不足就重新分配内存
{
this->_AllocateMem();
}
this->data[_Length] = *cstr;
this->_Length++;
cstr++;
}
this->data[this->_Length] = '\0';//字符串结束符
}
String::String(const String &str):String()//委托构造
{
strcpy(this->data, str.data);
this->reference_count = str.reference_count;
*this->reference_count = *this->reference_count + 1;//引用计数加1
this->_Length = str._Length;
this->_Size = str._Size;
}
String::~String()
{
/************************************************************************/
/* 如果引用计数等于1则说明当前是最后一个指向该存储区的对象,所以当对 */
/* 象销毁时应该释放该内存区 */
/************************************************************************/
if (*this->reference_count == 1)
{
delete[] this->data;//释放内存
delete this->reference_count;
this->data = nullptr;
this->reference_count = nullptr;
}
else
{
*this->reference_count = *this->reference_count - 1;
this->data = nullptr;
}
}
bool String::append(const String &str)//追加字符串
{
String temp(str);
while ((this->_Length + str._Length) >= this->_Size)
{
this->_AllocateMem();
}
strcpy(&this->data[this->_Length],str.data);//字符串拷贝
this->_Length += str._Length;//长度改变
this->data[this->_Length] = '\0';//字符串结束标识
return true;
}
bool String::insert(unsigned int pos, char args)//在pos之前插入字符
{
if (pos > this->_Length)//如果插入的位置超过了字符串长度,返回false
{
return "array over range";
}
for (unsigned int i = 0; i <= this->_Length - pos + 1; i++)//循环次数
{
this->data[this->_Length + 1 - i] = this->data[this->_Length - i];//遍历移动字符
}
this->data[pos - 1] = args;//插入字符
this->_Length++;
return true;
}
bool String::erase(unsigned int pos)//删除pos位置之前的一个字符
{
if (pos >= this->_Length)//如果删除的位置>=字符串长度,返回false
{
return "array over range";
}
for (unsigned int i = 0; i <= this->_Length - pos; i++)//循环次数
{
this->data[pos + i - 1] = this->data[pos + i];//遍历移动字符
}
this->_Length--;
return true;
}
bool String::assign(unsigned int pos, char c)//替换pos位置之前的一个字符串
{
if (pos >= this->_Length)
{
return "array over range";
}
this->data[pos - 1] = c;
return true;
}
unsigned int String::findc(char c)//返回字符c第一次出现的位置(逻辑位置)
{
unsigned int i = 0;
while (this->data[i] != c)//如果不是要查找的字符,就查看下一个
{
i++;
if (i >= this->_Length)//如果超过字符串长度,就返回错误
{
return 0;
}
}
return i + 1;//查找成功时,返回逻辑地址
}
unsigned int String::rfindc(char c)//返回字符c最后一次出现的位置
{
unsigned int i = this->_Length - 1;//指向最后一个字符
while (this->data[i] != c)//如果不是要查找的字符,就查看前一个
{
if (0 == i)//如果下标0的位置还不是要查找的字符就退出。(注意无符号整型不能再减减,否则会溢出)
{
return 0;
}
i--;
}
return i + 1;//查找成功时,返回逻辑地址
}
unsigned int String::compare(const String &str)//字符串比较,返回不一样的位置
{
unsigned int i = 0;
while (str.data[i] != '\0'&&this->data[i] != '\0')
{
if (str.data[i] != this->data[i])
{
return i + 1;
}
i++;
}
if (str.data[i] == '\0'&&this->data[i] == '\0')//若字符串同时结束,表示字符串一样,则返回0
{
return 0;
}
return i + 1;
}
unsigned int String::finds(const String &str)//匹配字符串第一次出现的位置
{
unsigned int i = 0, j = 0;
while (i < this->_Length&&j < str._Length)
{
if (this->data[i] == str.data[j])
{
i++;
j++;
}
else
{
i = i - j + 1;
j = 0;
}
}
if (j >= str._Length)
{
return i - str._Length + 1;
}
else
{
return 0;
}
}
char& String::operator[](unsigned int n)//下标访问,从0开始
{
if (n >= this->_Length)
{
throw "array over range";
}
return this->data[n];
}
bool String::operator==(const String &str)//判断字符串是否相等
{
if (this->_Length != str._Length)//如果长度不一样则字符串不相等
{
return false;
}
else
{
for (unsigned int i = 0; i < this->_Length; i++)//如果字符串长度相等
{
if (this->data[i] != str.data[i])
{
return false;
}
}
return true;
}
}
bool String::operator==(const char* cstr)//判断字符串是否相等
{
String str(cstr);
return *this == str;
}
bool String::operator!=(const String &str)//判断字符串不等
{
return !(*this == str);
}
bool String::operator<(const String &str)//判断字符串小于
{
unsigned int min = this->_Length < str._Length ? this->_Length : str._Length;
for (unsigned int i = 0; i < min; i++)
{
if (this->data[i]<str.data[i])
{
return true;
}
if (this->data[i]>str.data[i])
{
return false;
}
}
if (this->_Length < str._Length)
{
return true;
}
else
{
return false;
}
}
bool String::operator>(const String &str)//判断字符串大于
{
unsigned int min = this->_Length < str._Length ? this->_Length : str._Length;
for (unsigned int i = 0; i < min; i++)
{
if (this->data[i]>str.data[i])
{
return true;
}
if (this->data[i]<str.data[i])
{
return false;
}
}
if (this->_Length > str._Length)
{
return true;
}
else
{
return false;
}
}
bool String::operator>=(const String &str)//判断字符串大于等于
{
if (*this == str || *this > str)
{
return true;
}
else
{
return false;
}
}
bool String::operator<=(const String &str)//判断字符串小于等于
{
if (*this == str || *this < str)
{
return true;
}
else
{
return false;
}
}
String String::operator+(const String &str)
{
String temp;
temp += *this;
temp += str;
return temp;
}
const String& String::operator+=(const String &str)//字符串连接
{
this->append(str);
return *this;
}
const String& String::operator+=(const char* cstr)//字符串追加
{
String str(cstr);//构造字符串
this->append(str);//追加字符串
return *this;
}
const String& String::operator=(const String &str)//字符串赋值
{
this->~String();//释放内存空间(释放的时候根据引用计数判断)
this->data = str.data;//指向str的内存空间
this->reference_count = str.reference_count;//指向内存空间的引用计数器
*this->reference_count = *this->reference_count + 1;//引用计数加1
this->_Size = str._Size;//记录内存空间的单元大小
this->_Length = str._Length;//记录字符串的长度
return *this;
}
const String& String::operator=(const char* cstr)//字符串赋值
{
String str(cstr);
*this = str;
return *this;
}
std::ostream& operator<<(std::ostream &os, String &str)//输出字符串
{
os << str.data;//输出字符串
return os;//返回输出流的引用
}
std::istream& operator>>(std::istream &is, String &str)//输入字符串,用空格或回车间隔
{
String temp;
while (char c = is.get()!='\0')
{
if (temp._Length-1==temp._Size)
{
temp._AllocateMem();
}
temp.data[temp._Length] = c;
temp._Length++;//字符串长度
}
temp.data[temp._Length] = '\0';//字符串结束标识
str = temp;
return is;
}
写这篇文章主要是为了复习一下引用计数的使用
引用计数模型: