C++高级——探秘对象构造和析构(二)
对象作为参数或者返回值的处理
首先来看类的定义:
class Test
{
public:
// Test() Test(20)
Test(int data = 10) :ma(data)
{
cout << "Test(int)" << endl;
}
~Test()
{
cout << "~Test()" << endl;
}
Test(const Test &t):ma(t.ma)
{
cout << "Test(const Test&)" << endl;
}
void operator=(const Test &t)
{
cout << "operator=" << endl;
ma = t.ma;
}
int getData()const { return ma; }
private:
int ma;
};
主函数模块:
Test GetObject(Test &t)
{
int val = t.getData();
/* 在传参的过程中,不用引用的话会产生一次临时对象的生成过程 Test tmp(val); return tmp; 在返回值中,也会产生一次在main主函数栈帧上的临时对象 */
// 返回临时对象
return Test(val);
}
int main()
{
Test t1;
Test t2 = GetObject(t1);
//t2 = GetObject(t1);
return 0;
}
编写拷贝函数的规则:
- 函数参数传递过程中,对象优先按引用传递,不要按值传递
- 函数返回对象的时候,应该优先返回一个临时对象,而不要返回一个定义过的对象
- 接收返回值是对象的函数调用的时候,优先按初始化的方式接收,不要按赋值的方式接收
- 不能返回局部的或者临时对象的指针或引用
存在堆空间的对象作为返回值的情况
先看一个mystring类的定义:
class CMyString
{
public:
CMyString(const char *str = nullptr)
{
cout << "CMyString(const char*)" << endl;
if (str != nullptr)
{
mptr = new char[strlen(str) + 1];
strcpy(mptr, str);
}
else
{
mptr = new char[1];
*mptr = '\0';
}
}
~CMyString()
{
cout << "~CMyString" << endl;
delete[]mptr;
mptr = nullptr;
}
// 带左值引用参数的拷贝构造
CMyString(const CMyString &str)
{
cout << "CMyString(const CMyString&)" << endl;
mptr = new char[strlen(str.mptr) + 1];
strcpy(mptr, str.mptr);
}
// 带右值引用参数的拷贝构造
CMyString(CMyString &&str) // str引用的就是一个临时对象
{
cout << "CMyString(CMyString&&)" << endl;
mptr = str.mptr;
str.mptr = nullptr;
}
// 带左值引用参数的赋值重载函数
CMyString& operator=(const CMyString &str)
{
cout << "operator=(const CMyString&)" << endl;
if (this == &str)
return *this;
delete[]mptr;
mptr = new char[strlen(str.mptr) + 1];
strcpy(mptr, str.mptr);
return *this;
}
// 带右值引用参数的赋值重载函数
CMyString& operator=(CMyString &&str) // 临时对象
{
cout << "operator=(CMyString&&)" << endl;
if (this == &str)
return *this;
delete[]mptr;
mptr = str.mptr;
str.mptr = nullptr;
return *this;
}
const char* c_str()const { return mptr; }
private:
char *mptr;
};
主函数模块:
CMyString GetString(CMyString &str)
{
const char* pstr = str.c_str();
CMyString tmpStr(pstr);
return tmpStr;
}
int main()
{
CMyString str1("aaaaaaaaaaaaaaaaaaaa");
CMyString str2;
str2 = GetString(str1);
cout << str2.c_str() << endl;
return 0;
}
运行结果:
CMyString(const char*)
CMyString(const char*)
CMyString(const char*)
CMyString(const CMyString&) => tmpStr拷贝构造main函数栈帧上的临时对象
~CMyString
operator=(const CMyString&) => main函数栈帧上的临时对象给t2赋值
~CMyString
aaaaaaaaaaaaaaaaaaaa
~CMyString
~CMyString
结论:在有内存开销的对象作为返回值的情况下,返回的临时对象会被以右值引用的方式将自我的资源移交给新对象,大体上就是拷贝地址,原指针置为空。
参考文献
[1] 施磊.腾讯课堂——C++高级.图论科技,2020.7.