一、普通String类型
#include<assert.h>
//string类型
class String
{
char* str; //new FILE *fp thread(要重写拷贝和赋值,防止出现浅拷贝和浅赋值)
String(char* s, int)
{
str = s;
}
public:
String(const char* s = nullptr)
{
if (s != nullptr)
{
int len = strlen(s) + 1;
str = new char[len];
strcpy_s(str, len, s); //len是str开辟的空间长度
}
else
{
str = new char[1]; //仅指向一个字节
this->str[0] = '\0'; //一定让他不为空,指向指向'\0'的一个空串
//否则赋值,拷贝等,都要考虑四种情况,谁为不为空
//eg:s1 NULL s2 "defe"
//this->str = '\0';是将其置为空指针
}
}
~String()
{
if (str != nullptr)
{
delete[] str;
}
str = nullptr;
}
String(const String& s) //浅拷贝
{
//str = s.str; //共享资源,共享内存空间,会有重复释放的问题
if (s.str != nullptr) //深拷贝
{
int len = strlen(s.str) + 1;
str = new char[len];
strcpy_s(str, len, s.str); //len是str开辟的空间长度
}
}
String& operator = (const String& s)
{
if (this!= &s)
{
//str = s.str; //浅赋值
delete[] str; //深赋值
int len = strlen(s.str) + 1;
str = new char[len];
strcpy_s(str, len, s.str);
}
return *this;
}
//移动构造:是资源的移动(减轻对堆区不断开辟释放的过程)
String(String&& s)
{
str = s.str;
s.str = nullptr;
}
//移动赋值
String& operator=(String&& s)
{
if (this != &s)
{
delete[] str;
str = s.str;
s.str = nullptr;
}
return *this;
}
String operator+(const String& s) const
{
int total = strlen(this->str) + strlen(s.str) + 1;
char* sp = new char[total];
strcpy_s(sp, total, this->str);
strcat_s(sp, total, s.str);
//return String(sp) //调动构造产生一个临时对象,sp指向的空间就没有释放掉
return String(sp, 1); //构建的临时对象的str将指向sp,将此对象赋给s3,资源移动
} //对象+对象
String operator+(const char* s) const //对象+变量
{
return *this + String(s);
}
String& operator+=(const String& s)
{
char* tmp = this->str;
int total = strlen(tmp) + strlen(s.str) + 1;
str = new char[total];
strcpy_s(str, total, tmp);
strcat_s(str, total, s.str);
delete[] tmp; //tmp是原来str指向的资源
return *this;
} //s1 += s2
String& operator+=(const char* s) //对象+=变量
{
return *this += String(s);
}
char& operator[] (const int index) const
{
assert(index >= 0 && index < strlen(this->str));
return str[index];
}
const char& operator[] (const int index) const
{
assert(index >= 0 && index < strlen(this->str));
return str[index];
}
ostream& operator<<(ostream& out) const
{
out << str;
return out;
} //s1<<cout; s1.operator<<(cout);operator<<(&s1,cout)
};
//设为全局函数,放入类中作为成员函数,参数列表省略了this指针,将变为3个参数
String operator+(const char* s, const String& st) //变量+对象
{
return String(s) + st;
}
String fun()
{
String tmp("nswubd");
return tmp;
}
ostream& operator<<(ostream& out, const String& s)
{
s << cout;
return cout;
}
int main()
{
//String s1("wejbfwue");
//String s2("dneide");
//String s3(s1);
String s1 = fun(); //构建的临时对象就是s1,移动赋值
String s2("tulun");
s2 = fun(); //深拷贝,tmp赋给临时对象,析构掉tmp,把临时对象赋给s2,把临时对象的资源给s2
String s1("dheudh");
s1 = std::move(s2); //当没写赋值语句时,缺省的移动赋值(不好用,要重写):是将字符串拷贝到s1所指向的空间,不会删除s2的资源,将内容直接拷贝
String s4("wbfuwf");
String s5("ejiwdewdw");
s4 = s5; //调用普通的赋值语句,因为s5有名字,不能进行右值引用
String s6; //s6中放的是‘\0’
s6 = s4 + s5;
s4 += s5;
cout << s1 << endl; //输出
return 0;
}
写赋值函数时都要考虑四种情况:
not not
not nullptr
nullptr not
nullptr nullptr
二、字符数组为柔性数组的String
class String
{
//柔性数组
struct StrNode
{
int len; //字符串的长度
int size; //字符串的空间大小
int ref; //引用计数
char data[]; //柔性数组, 定义在最后
};
private:
StrNode* str;
String(StrNode* s)
{
str = s;
}
public:
String(const char* s = nullptr): str(nullptr)
{
if (s != nullptr)
{
int len = strlen(s) + 1;
str = (StrNode*)malloc(sizeof(StrNode) + 2 * len);
if (str == nullptr) exit(EXIT_FAILURE);
str->len = len;
str->size = 2 * len;
str->ref = 1;
strcpy_s(str->data, 2 * len, s);
}
}
~String()
{
if (str != nullptr && -- this->str->ref == 0)
{
free(this->str);
}
str = nullptr;
}
String(const String& s) :str(s.str)
{
if (str != nullptr)
{
str->ref += 1;
}
}
String& operator=(const String& s)
{
if (this != &s)
{
if (str != nullptr && --str->ref == 0)
{
free(str);
}
str = s.str;
if(str != nullptr)
{
str->ref += 1;
}
}
return *this;
} //s1 =s2(四种情况)
//移动
String(String&& s)
{
if (str != nullptr && --str->ref == 0)
{
free(str);
}
str = s.str;
s.str = nullptr;
}
String& operator=(String&& s)
{
if (this != &s)
{
if (str != nullptr && --str->ref == 0)
{
free(str);
}
str = s.str;
s.str = nullptr;
}
return *this;
}
String operator+(const String& s) const
{
//先开size
int total = 1;
if (str != nullptr) total += str->len;
if (s.str != nullptr) total += s.str->len;
StrNode* sp = (StrNode*)malloc(sizeof(StrNode) + 2 * total);
if (sp == nullptr) exit(EXIT_FAILURE);
if (str != nullptr) strcpy_s(sp->data, 2 * total, str->data);
if (s.str != nullptr) strcat_s(sp->data, 2 * total, s.str->data);
//设置StrNode的变量的值
sp->len = total - 1;
sp->size = 2 * total;
str->ref = 1;
return String(sp);
} //四种情况
};
int main()
{
String s1("iewbd");
String s2("iewbciwebc");
String s3;
String s4(s1);
String s5(s2);
s3 = s1 + s2;
//s3 = s1 + "neonwoi";
//s3 = "oenw" + s1;
s1 += s2;
//s1 += "iedi";
return;
}