代碼1 #include <iostream> using namespace std; class MyString3 { public: MyString3(const char * pChar=nullptr) { if (pChar == nullptr) { this->pString = ...
代碼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,避免了像左值拷貝構造一樣 一次堆記憶體的開闢