<三>关于对象优化

代码1

#include <iostream>
using namespace std;
class MyString3 {
public:
	MyString3(const char * pChar=nullptr) {
	if (pChar == nullptr) {
	this->pString = new char[1];
	this->pString[0] = '\0';
	
	}
	else {
	int len = strlen(pChar);
	this->pString = new char[len + 1];
	strcpy(this->pString, pChar);
	}	
	cout << "MyString 构造函数" << endl;
	}
	// 左值拷贝构造
	MyString3(const MyString3 & _rval) {
	int len = strlen(_rval.pString);
	this->pString = new char[len + 1];
	strcpy(this->pString, _rval.pString);
	cout << "MyString 左值拷贝构造函数" << endl;
	}
	//左值赋值重载函数
	MyString3 & operator =(const MyString3 & _rval) {
	cout << "MyString 左值赋值重载函数" << endl;
	if (this == &_rval) { return *this; }
	else {
	
	delete[]this->pString;
	this->pString = nullptr;
	
	int len = strlen(_rval.pString);
	char *tep = new char[len + 1];
	strcpy(tep,_rval.pString);
	this->pString = tep;	
	
	return *this;
	}
	
	}
	const char * c_str() {
	return pString;
	}
	
	~MyString3() {
	cout << "MyString 析构函数" << endl;
	delete[] this->pString;
	pString = nullptr;
	}
private:
	char *pString;
};
MyString3 getMyString(MyString3 & ms) {
	const char * tep = ms.c_str();
	MyString3 S(tep);
	return S;
}
int main() {
	MyString3 S1("ABCDEF123456");
	MyString3 S2;
	S2=getMyString(S1);
	system("pause");
	return 0;
}

上面出现大量重复的空间开辟和析构过程.

如何解决上面的问题?

先回顾一下以前关于左值引用,和右值引用
int a =10;
int & ra=a;
左值,有名字,有地址 如a ,可以将左值引用绑定到一个左值上
int &b =100;//错误 不能将左值引用绑定到一个右值,100是右值
右值:没有名字,没有地址
int &&rb=100;//ok 将右值引用绑定到 右值
int &&rb=a;//错误,不能将右值引用绑定到左值
int &b =100 //错误, 如果要想可以 需要 const int &b =100; 编译器其实生成了一个 临时量 int tep=100; int &b=tep;
同理
// 不可以,因为C++编译器将匿名对象都看做右值,所以要 MyString3 && rs=MyString3;或者 const MyString3 &s=MyString3;
MyString3 &s=MyString3("ABC");

代码2

#include <iostream>
using namespace std;
class MyString3 {
public:
	MyString3(const char * pChar=nullptr) {
	if (pChar == nullptr) {
	this->pString = new char[1];
	this->pString[0] = '\0';
	
	}
	else {
	int len = strlen(pChar);
	this->pString = new char[len + 1];
	strcpy(this->pString, pChar);
	}	
	cout << "MyString 构造函数" << endl;
	}
	// 左值拷贝构造
	MyString3(const MyString3 & _rval) {
	int len = strlen(_rval.pString);
	this->pString = new char[len + 1];
	strcpy(this->pString, _rval.pString);
	cout << "MyString 左值拷贝构造函数" << endl;
	}
	// 右值拷贝构造, MyString3 && _rval 这个形参,右值引用 匹配 的是 临时对象
	MyString3(MyString3 && _rval) {
	//由于临时对象声明周期 只在当前语句,出了当前语句就销售了
	//所以我们可以复用他开辟的堆空间,避免重复开辟
	this->pString = _rval.pString;
	_rval.pString = nullptr;//要置空,避免多个MyString 对象指向同一个堆空间
	cout << "MyString 右值拷贝构造函数" << endl;
	}
	//左值赋值重载函数
	MyString3 & operator =(const MyString3 & _rval) {
	cout << "MyString 左值赋值重载函数" << endl;
	if (this == &_rval) { return *this; }
	else {
	
	delete[]this->pString;
	this->pString = nullptr;
	
	int len = strlen(_rval.pString);
	char *tep = new char[len + 1];
	strcpy(tep,_rval.pString);
	this->pString = tep;	
	
	return *this;
	}
	
	}
	//右值赋值重载函数 MyString3 && _rval 这个形参,右值引用 匹配 的是 临时对象
	MyString3 & operator =(MyString3 && _rval) {
	cout << "MyString 右值赋值重载函数" << endl;
	if (this == &_rval) { return *this; }
	else {
	//由于临时对象声明周期 只在当前语句,出了当前语句就销售了
	//所以我们可以复用他开辟的堆空间,避免重复开辟
	this->pString = _rval.pString;
	_rval.pString = nullptr;//要置空,避免多个MyString 对象指向同一个堆空间
	return *this;
	}
	}
	const char * c_str() {
	return pString;
	}
	
	~MyString3() {
	cout << "MyString 析构函数" << endl;
	delete[] this->pString;
	pString = nullptr;
	}
private:
	char *pString;
};
MyString3 getMyString(MyString3 & ms) {
	const char * tep = ms.c_str();
	MyString3 S(tep);
	return S;
}
int main() {
	MyString3 S1("ABCDEF123456");
	MyString3 S2;
	S2=getMyString(S1);
	system("pause");
	return 0;
}


通过右值引用,避免了一些内存重复开辟

代码3

MyString3 operator +(const MyString3 & ls,const MyString3 rs) {
	char * tp = new char[strlen(ls.pString) + strlen(rs.pString) + 1];
	strcpy(tp, ls.pString);
	strcat(tp, rs.pString);
	return MyString3(tp);
}
ostream & operator <<(ostream &out, const MyString3 & s) {
	cout << s.c_str() << endl;
	return out;
}
int main() {
	MyString3 S1("ABCDEF");
	MyString3 S2=("1234");
	
	MyString3 S3 = S1 + S2;
	cout << S3 <<"S3地址 ="<<&S3 << endl;
	system("pause");
	return 0;
}
在MyString 中加入 + 法操作,上面的 operator +()函数有问题, tp 没有 delete 内存泄漏了
修改如下
MyString3 operator+ (const MyString3 & ls, const MyString3 & rs) {
	char * tp = new char[strlen(ls.pString) + strlen(rs.pString) + 1];
	strcpy(tp, ls.pString);
	strcat(tp, rs.pString);
	MyString3 ts(tp);
	delete[]tp;
	cout << " operato + " << endl;
	return ts;
}
//修改完成后 tp 指针能正常释放内存, 但是多构建了MyString3 ts(tp);对象,继续优化,执行结果如下第二张图
MyString3 operator+ (const MyString3 & ls, const MyString3 & rs) {
 MyString3 ts;
	ts.pString= new char[strlen(ls.pString) + strlen(rs.pString) + 1];
	strcpy(ts.pString, ls.pString);
	strcat(ts.pString, rs.pString);
	cout << " operato + " << endl;
	return ts;
}
MyString3 S3 = S1 + S2; //operator+ 返回的ts对象会使用 右值拷贝构造创建 S3,避免了像左值拷贝构造一样 一次堆内存的开辟

作者:Hello_Bugs原文地址:https://www.cnblogs.com/erichome/p/16941408.html

%s 个评论

要回复文章请先登录注册