1. 为什么会有string类

  1. 处理char型数组,封装标准C中一些字符串处理函数。

  2. 容器


2. 规格:有106个成员接口函数。

有如此之多的原因:

  1. 提高效率。(设计比较冗余,为了追求效率,省去了调用构造/析构函数及分配/释放内存的时间)

  2. 用于实现常用操作


3.实现:C++标准没有过多干预,不同厂商有不同实现。


4.缺陷

  1. 不支持多进/线程;

  2. 模板技术水平没跟上;

  3. 接口函数设计比较冗余,同一个功能上实现了多次,而有一些功能却没有实现,且陷阱多;

  4. 不支持虚函数,阻止了多态性;

  5. 加剧了内存碎片问题。希望String类拥有自己的栈上内存来存放一些短字符串,而不需要总是去堆上分配内存。

  6. 采用的Copy-On-WriteCOW)技术,因为内存的共享,导致了程序在“多线程”环境中及容易发生错误,如果分别在两个线程中的string实例共享着同一块内存,很有可能发生潜在的内存问题。

  7. 标准的string类不支持policy-base技术的错误处理。string遇到错误时,只是简单地抛出异常。不可能要且要求所有的程序都要在使用string操作的时候try catch。解决建议:string类封装自己的error-handling函数,并且可以让用户来定义使用哪一种错误处理机制。


5.String类的简单实现

#include
using namespace std;
class String
{
public:
	String();
	String(const char* str);
	~String();
	String(const String& s);
	String &operator=(const String & s);
private:
	char* _str;
};
String::String()
:_str(new char[1])
{
	//cout << "无参构造函数" << endl;
	_str = '\0';
}
String::String(const char* str = "")
    : _str(new char [strlen(str)+1])
{
	//cout << "带参构造函数" << endl;
	strcpy(_str,str);
}
String::~String()
{
	//cout << "析构函数" << endl;
	delete[] _str;
}
String::String(const String& s)
    :_str(new char[strlen(s._str)+1])
{
	//cout << "拷贝" << endl;
	strcpy(_str,s._str);
}
//String& String::operator=(const String & s)
//{
//	cout << "一般赋值运算符重载" << endl;
//	//检查自赋值
//	if (this == &s)
//		return *this;
//	//释放原有的内存资源
//	delete[] _str;
//	//分配新的内存资源,并复制内容
//	_str = new char[strlen(s._str) + 1];
//	strcpy(_str, s._str);
//	//返回本对象的引用
//	return *this;
//}

//赋值的现代写法
String& String::operator=(const String & s)
{
	//cout << "现代赋值运算符重载" << endl;
	if (this == &s)
		return *this;
	//创建临时变量,用于交换
	String strtmp(s);
	char* ptmp = strtmp._str;
	strtmp._str = _str;
	_str = ptmp;
	//返回本对象的引用
	return *this;
}
int main()
{
	String s1("hello");

	String s2(s1);

	String s3 = s1;

	s1 = s2;

	system("pause");
	return 0;
}

输出结果:

(1)一般赋值运算符重载函数

wKioL1dmVSyzI-srAAAMXXdUw10541.png

(2)现代赋值运算符重载函数


实现表明:

  1. 在现代赋值运算符重载函数中,创建了一个临时String对象(运用了拷贝构造函数),因为此临时String对象的作用域为整个现代赋值运算符重载函数,出了这个函数就调用析构函数释放内存资源,所以,现代赋值运算符重载函数比一般赋值运算符重载函数多两个输出。

  2. 第三行:String s3 = s1;我们明明是想用赋值运算符重载,实际调用的却是拷贝构造函数。这是因为编译器优化的缘故,把本需调用构造函数构造s3再调用赋值运算符重载函数把s1拷贝给s3,编译器直接优化为利用拷贝构造函数构造s3。