请记住
绝不要返回pointer或者reference指向一个local stack 对象(因为已经离开生命周期),
或返回reference指向一个heap-allocated对象(因为要承担释放内存的责任),
或返回pointer或者reference指向local static对象。
请记住
当你必须在返回一个reference或者object之间抉择时,你的工作就是挑出行为正确的那个。
让编译器厂商为尽可能降低成本鞠躬尽瘁吧,你可以享受你的生活。
实际上,现代编译器也做了优化。
当局部变量接收局部变量的时候,函数内的局部变量不会析构,而是直接把整个对象传出去,也不会重新执行构造。
#include <string>
#include <iostream>
using namespace std;
class AuthInfo {
public:
AuthInfo(int a, bool b): m_a(a), m_b(b) {
cout << "AuthInfo is called" << endl;
}
AuthInfo(const AuthInfo& a) {
m_a = a.m_a;
m_b = a.m_b;
cout << "copy construct is called" << endl;
}
AuthInfo& operator = (const AuthInfo& a) {
m_a = a.m_a;
m_b = a.m_b;
cout << "operator construct is called" << endl;
return *this;
}
~AuthInfo() {
cout << "Deonstruct is called" << endl;
}
private:
int m_a;
bool m_b;
};
AuthInfo getAuth()
{
AuthInfo a(1,0);
cout << "&a = " << &a << endl;
return a;
}
int getInt()
{
int b = 100;
cout << "&b = " << &b << endl;
return b;
}
int main()
{
AuthInfo a1 = getAuth(); // 编译器实际是有优化的, a1没有再一次调用构造函数,直接使用了已经构造过的局部变量a,局部变量a也没有调用析构函数
cout << "&a1 = " << &a1 << endl; // a1和局部变量a的地址完全一样.
cout << endl;
int b1 = getInt(); // 对应内置类型int,编译器就没有做过类似上面的优化了
cout << "&b1 = " << &b1 << endl; // b1和局部变量b的地址是不同的
cout << endl;
return 0;
}
运行结果
用非引用接收非引用的局部变量,既没有发生析构,也没有发生重新构造。
但如果返回的是静态变量,那么会重新构造
#include <string>
#include <iostream>
using namespace std;
class AuthInfo {
public:
AuthInfo(int a, bool b): m_a(a), m_b(b) {
cout << "AuthInfo is called" << endl;
}
AuthInfo(const AuthInfo& a) {
m_a = a.m_a;
m_b = a.m_b;
cout << "copy construct is called" << endl;
}
AuthInfo& operator = (const AuthInfo& a) {
m_a = a.m_a;
m_b = a.m_b;
cout << "operator construct is called" << endl;
return *this;
}
~AuthInfo() {
cout << "Deonstruct is called" << endl;
}
private:
int m_a;
bool m_b;
};
AuthInfo getStaticAuth(bool staticFlag)
{
if (staticFlag) {
static AuthInfo staticA(46,0);
cout << "&staticA = " << &staticA << endl; // 返回静态变量
return staticA;
} else {
AuthInfo a(1,0);
cout << "&a = " << &a << endl;
return a;
}
}
int main()
{
AuthInfo a2 = getStaticAuth(true); // 返回的是static变量,会调用构造函数,重新生成
cout << "&a2 = " << &a2 << endl;
cout << endl;
AuthInfo a3 = getStaticAuth(false); // 返回的是局部变量,会直接被a3接收,不会重新析构和构造
cout << "&a3 = " << &a3 << endl;
cout << endl;
return 0;
}
如果返回的是一个对象中的一部分,那么也会重新构造。就算是引用接收也没有用。
struct AuthContainer
{
AuthInfo auth;
int int_temp;
AuthContainer(int a, bool b, int c) : auth(a,b), int_temp(c)
{
};
};
AuthInfo getAuthFromAuth()
{
AuthInfo a(789,0); // 构造
cout << "address of a is : " << &a << endl;
return a;
}
AuthInfo getAuthFromAStruct()
{
AuthContainer b(0,1,2);
cout << "address of b.auth is : " << &b.auth << endl;
return b.auth;
}
int main() {
AuthInfo b1 = getAuthFromAStruct(); // 非引用接收会重新构造
cout << "address of b1 is : " << &b1 << endl;
const AuthInfo& b2 = getAuthFromAStruct(); // 引用接收也会重新构造
cout << "address of b2 is : " << &b2 << endl;
return 0;
}
运行结果
局部变量不能返回引用
- 首先会有编译告警
- 其次局部变量会析构调。
#include <string>
#include <iostream>
using namespace std;
class AuthInfo {
public:
AuthInfo(int a, bool b): m_a(a), m_b(b) {
cout << "AuthInfo is called" << endl;
}
AuthInfo(const AuthInfo& a) {
m_a = a.m_a;
m_b = a.m_b;
cout << "copy construct is called" << endl;
}
AuthInfo& operator = (const AuthInfo& a) {
m_a = a.m_a;
m_b = a.m_b;
cout << "operator construct is called" << endl;
return *this;
}
~AuthInfo() {
cout << "Deonstruct is called" << endl;
}
private:
int m_a;
bool m_b;
};
AuthInfo& getAuth() // 局部变量返回引用
{
AuthInfo a(1,0);
cout << "&a = " << &a << endl;
return a;
}
int main()
{
AuthInfo& a1 = getAuth();
cout << "&a1 = " << &a1 << endl;
cout << endl;
return 0;
}
运行结果
上面的例子是使用引用接收返回,如果不用引用接收返回值,那么就是用一个已经析构的对象,去初始化对象。
#include <string>
#include <iostream>
using namespace std;
class AuthInfo {
public:
AuthInfo(int a, bool b): m_a(a), m_b(b) {
cout << "AuthInfo is called" << endl;
}
AuthInfo(const AuthInfo& a) {
m_a = a.m_a;
m_b = a.m_b;
cout << "copy construct is called" << endl;
}
AuthInfo& operator = (const AuthInfo& a) {
m_a = a.m_a;
m_b = a.m_b;
cout << "operator construct is called" << endl;
return *this;
}
~AuthInfo() {
cout << "Deonstruct is called" << endl;
}
private:
int m_a;
bool m_b;
};
AuthInfo& getAuth() // 局部变量返回引用
{
AuthInfo a(1,0);
cout << "&a = " << &a << endl;
return a;
}
int main()
{
AuthInfo a1 = getAuth(); // 用非引用接收引用
cout << "&a1 = " << &a1 << endl;
cout << endl;
return 0;
}
运行结果
用已经析构的对象初始化函数接收对象
有一种情况是用引用变量去接收return by value,从运行结果看,和使用value去接收value的情况一直,既不会发生析构,也不会发生重新构造。 不知这种用法是否是推荐的。
#include <string>
#include <iostream>
using namespace std;
class AuthInfo {
public:
AuthInfo(int a, bool b): m_a(a), m_b(b) {
cout << "AuthInfo is called" << endl;
}
AuthInfo(const AuthInfo& a) {
m_a = a.m_a;
m_b = a.m_b;
cout << "copy construct is called" << endl;
}
AuthInfo& operator = (const AuthInfo& a) {
m_a = a.m_a;
m_b = a.m_b;
cout << "operator construct is called" << endl;
return *this;
}
~AuthInfo() {
cout << "Deonstruct is called" << endl;
}
private:
int m_a;
bool m_b;
};
AuthInfo getAuth() // 局部变量返回非引用
{
AuthInfo a(1,0);
cout << "&a = " << &a << endl;
return a;
}
int main()
{
const AuthInfo& a1 = getAuth(); // 用引用接收非引用
cout << "&a1 = " << &a1 << endl;
cout << endl;
return 0;
}
总结
- local对象不能返回引用。
- local对象返回值的时候,使用值接收,编译器会有优化,既不会发生局部变量的析构,也不会发生接收值的构造。
- static的local对象返回值的时候,使用值接收,会发生接收值的重新构造。
- 特别的,local对象返回值的时候,可以用const的引用类型接收,这个过程中既不会发生局部变量的析构,也不会发生接收值的构造,不知是为何?? 不知道是否是一种推荐的做法。