防火、防盗、防拷贝;懂你,懂我,懂临时
测试代码:
#include <iostream>
using namespace std;
class testCopy
{
public:
int i;
int j;
public:
testCopy(int m = 0, int n = 0);
testCopy(const testCopy &ts)
{
this->i = ts.i;
this->j = ts.j;
cout << "拷贝构造函数被执行!" << endl;
}
testCopy & operator=(const testCopy& ts)
{
i = ts.i;
j = ts.j;
cout << "拷贝赋值运算符执行!" << endl;
return *this;
}
virtual ~testCopy()
{
cout << "析构函数被执行!" << endl;
}
public:
int Add1(testCopy ts);
int Add2(testCopy& ts)
};
testCopy::testCopy(int m, int n) : i(m), j(n)
{
cout << "构造函数被执行!" << endl;
cout << "i = " << i << endl;
cout << "j = " << j << endl;
}
int testCopy::Add1(testCopy ts)
{
int sum = ts.i + ts.i;
ts.i = 1000;
return sum;
}
int testCopy::Add2(testCopy& ts)
{
int sum = ts.i + ts.i;
ts.i = 1000;
return sum;
}
一、传值还是传引用
对于上文中的测试代码我们可以发现,两个Add函数的不同在于形参是值或者引用,以下就来测试两种传递方式带来的结果。
int main()
{
testCopy myobj(10, 20);
int sum1 = myobj.Add1(myobj);
cout << "sum1=" << sum1 << endl;
cout << "myobj.i = " << myobj.i << endl;
cout << "-----------------------------------------" << endl;
int sum2 = myobj.Add2(myobj);
cout << "sum2=" << sum2 << endl;
cout << "myobj.i = " << myobj.i << endl;
return 0;
}

- return 0;时的析构函数未被呈现!
- 我们可以很容易的发现,让我们使用传值的方式给函数传递参数时,函数使用传入的myobj拷贝构造了一个临时对象ts,用这个临时进行操作,当然,我们修改i的值,仅仅修改了临时对象ts中的 i 值,并未对myobj造成影响。函数结束后,该临时对象生命周期结束,随之调用析构函数。
- 提升效率的方法是:使用传引用的方式给函数传递参数。从结果中我们容易发现,并没有拷贝构造函数执行,这是因为我们直接把myobj交给了函数进行操作,这样修改 i 值的时候,myobj的i值被修改为1000 。
二、类型转换生成临时对象
int main()
{
testCopy myobj2;
myobj2 = 1000; //构造临时对象
cout << "=========================================" << endl;
testCopy myobj3 = 1000;
getchar();
return 0;
}

- 当我们在执行 myobj2 = 1000; 语句时,系统使用1000构造了一个临时对象,然后在使用拷贝赋值运算符将该临时对象拷贝赋值给 myobj2 。
- 提升效率的方法是,直接在声明myobj2的时候就传入初值1000,这样系统不会生成临时对象,不会调用拷贝赋值运算符,这个等号的语义是:定义时初始化。
三、隐式类型转换以保证函数调用成功
int calculate(const string& source, char ch)
{
const char *p = source.c_str();
int icount = 0;
return icount;
}
int main()
{
char mystr[100] = "I Love China,oh,baby!";
int result = calculate(mystr, 'o');
getchar();
return 0;
}
我们发现,传入的实参与函数接收的形参类型并不相同,而编译器没有报错,这之中有什么悬机呢?
- 原来 int result = calculate(mystr, ‘o’); 这里系统会使用mystr来构造一个string类型的临时变量,再将此临时变量的引用链接上形参source,传入函数。(前提是形参是一个const修饰的常量,如果没有const将失败!)
- 为什么不加const会失败呢?原因是:不加const时,系统会认为你有修改系统创建的string类型临时变量的倾向,这是万万不被允许的!怎么能修改一个系统产生的临时对象呢?所以c++只会为const引用产生临时变量。
- 我们需要避免这种情况发生,老老实实传入相同类型的变量,不要给系统增加负担!
四、函数返回对象时
testCopy Double1(testCopy& ts)
{
testCopy temp;
temp.i = ts.i * 2;
temp.j = ts.j * 2;
return temp;
}
int main()
{
//(1)
testCopy myobj4(10, 20);
Double1(myobj);
cout << "=========================================" << endl;
//(2)
testCopy myobj5(10, 20);
testCopy myobj6 = Double1(myobj);
getchar();
return 0;
}

- return 0;时的析构函数不被呈现!
- 情况(1)中,返回对象时,系统使用temp拷贝构造了一个临时对象,temp在Double函数结束时,随即被析构,而因为没有使用对象来接收,这个临时对象随即被析构。
- 情况(2)中,我们创建了对象来myobj6来接收,那么此时系统构造的临时对象不会被立刻析构,而是与myobj6作用域相同。可以认为,这个临时对象使用了myobj6的预留空间,不会自己创建新空间。
- 接下来我们要提升效率
testCopy Double2(testCopy& ts)
{
return testCopy(ts.i * 2, ts.j * 2);
}
int main()
{
//(1)
testCopy myobj4(10, 20);
Double2(myobj);
cout << "=========================================" << endl;
//(2)
testCopy myobj5(10, 20);
testCopy myobj6 = Double2(myobj);
getchar();
return 0;
}

- return 0;时的析构函数不被呈现!
- 这样效率得到了提升,没有临时对象被构造。
本文探讨C++中临时对象的生成与管理,包括函数参数传递方式、类型转换、函数返回对象时的效率问题及如何优化。通过实例分析,揭示了传引用比传值更高效,直接初始化优于拷贝赋值,以及函数返回对象时的优化策略。
3031

被折叠的 条评论
为什么被折叠?



