catalog
- 函数返回值
- 返回值是`[const] T &`
- 返回值的类型是 T
- 返回的对象是 局部对象
- 实现原理
- 返回的对象是 全局对象
- 实例
函数返回值
返回值是[const] T &
ST operator*( ST & a, ST & b){
return ST( a.data * b.data);
}
ST a, b;
当你实际使用时: ST ret = a * b;
一共会有2次的 构造函数: 一次是ret
一次是函数返回值的temp临时对象
我们知道, 这个temp临时对象
, 肯定是徒劳的, 是否可以优化 把它去掉呢???
错误做法1
ST & operator*( ST & a, ST & b){
return ST( a.data * b.data);
}
返回一个: 指向临时对象的(引用/指针), 这自然是错误的; 因为临时对象,马上释放, 引用已经释放的内存 报错
错误做法2
ST & operator*( ST & a, ST & b){
return *( new ST( a.data * b.data));
}
当遇到a * b * a
时, 此时, a * b
这个对象 用户就没有得到他, 他是匿名对象, 自然也就无法释放了. 造成: 内存泄漏
错误做法3
ST & operator*( ST & a, ST & b){
static ST ret( a.data * b.data);
return ret;
}
当遇到: if( a * b == c * d)
时, 返回值永远是true.
因为, 所有operator函数的调用, 返回值都是同一个对象ret!!!
ret的值, 为, 最后一次 调用 operator函数的 值.
所以, if( a * b == c * d)
, 其实他的本质是: if( c * d == c * d)
错误
所以, 请永远不要: 试图通过返回const T &
来 减少临时对象 优化程序
返回ST &
, 只有1个场景:
class ST{
Obj data;
Obj & get_data(){ return data;} ' 即, 返回的这个对象, 在该函数调用前 (已经)存在了!!! '
};
如果, 就是要优化 减少临时对象, 只有1种做法:
void func_multiply( ST & a, ST & b, ST & ret){
ret.data = a.data * b.data;
}
ST a, b;
当你调用时: ST ret;
func_multiply( a, b, ret);
返回值的类型是 T
返回值是T
的意思是: 返回值是T, 不是T *
T &
返回的对象是 局部对象
ST Get(){
ST ret;
return ret;
}
当你调用Get();
时, 总共只会产生1个对象即ret
即: 函数返回给外部的对象, 就是这个ret对象本身
即, 你ST t = Get();
时, 右侧的这个Get()
所代表的对象 就是ret本身
这里好像很难理解, 因为此时的ST t = Get();
, 右侧的ret对象
已经超出了 他的作用域!!!
你应该这样理解: return语句, 并不是一个函数的结束, 函数的结束 是取决于: 函数的右括号}
ST Get(){
ST ret;
return ret;
}
ST t = Get(), func1(), func2();
首先一点是肯定的: 接收到ret的析构函数, 就意味着: Get函数的结束
执行流程是:
- 进入Get函数, 到return这行语句时,
将ret这个对象 本身
, 返回给ST t
这个对象 注意, 此时Get函数, 并没有结束!!!
即, return就像是: 发送了一个信号, 这个信号 带着ret
对象本身 返回到 原先切入点, 同时, 将ret这个对象 "标记"为: 临时对象 - 然后, 紧接着 ,执行 func1, func2, 直到执行到
;
结束 -
重点: 此时, 会返回到
Get
函数里, 然后遇到}
, 这个ret
才会 delete掉
即, return语句, 就像是Qt里的 [信号与槽], 他会跳到别的地方执行, 执行完后, 还会回来的!!!
Foo Get(){
Foo a;
return a; ' 或 return Foo(); 一样的 '
};
当你外界 Foo b = Get();
, 全程只有1个对象a
产生!!! (只有1个析构函数, 1个无参构造函数)
首先, 这确实是非常的 不可思议!!! (但是, 逻辑来讲, 这非常的合理!!)
因为, 你的目的, 就是让 a 和 b
两个对象 是相同的; 而, 如果 能用1个对象完成, 那肯定比用2个对象完成, 要好的多
一定要牢记这个知识点!!!
ST Get(){ ST o; return o;}
vector< ST> Get(){ vector< ST> o; return 0;}
' 一定要写成: '
ST ret = Get(); ' &ret == &o '
vector< ST> ret = Get(); ' &ret[0,1,2,..] == &o[0,1,2,..] '
' 这里的这个=等号, 不会引发任何的 对象构造复制 '
-------
' 千万不要写成: '
ST ret; ret = Get();
vector< ST> ret; ret = Get();
' 天壤差别, 造成 (对象复制) '
实现原理
暂时还不知道…
我猜可能是: 你虽然是写成ST a = Get(); vector< ST> b = Get();
但是, 其实他是会变成: ST && a = Get(); vector< ST> && b = Get();
返回的对象是 全局对象
ST g;
ST Get(){
return g;
}
这种写法, 和 把 ST g, 放到Get函数里
, 是天壤之别的!!!
程序一开始, g的构造
; 然后执行: Get();
的 return g
时, 返回的 并不是g!!!
而是会调用一次ST的构造
, 即构造一个新的临时对象, 给返回回去.
反问, 如果说, 返回的就是g
本身. 那么&Get()
是可以的, 而且Get().set_xxx()
会修改 全局变量g
的值.
这个功能, 应该是: ST & Get()
; 而此时是: ST Get()
; 这并不符合ST Get()
函数的 定义.
所以, 当ST Get(){ return obj;}
返回的obj, 是一个全局对象时, 他会构造一个临时对象 给返回
再比如说:
class Bar{
Foo foo;
Foo get_foo(){ return foo;}
};
当你调用 bar.get_foo();
时, 返回的, 并不是本身, 而是会构造一个(临时对象)
拷贝构造
, 返回回去
总之: Foo get(){ return ret;}
不管这个函数, 是全局/member函数
对于这个get(){}
函数作用域来说
- 如果这个
ret
, 是这个get作用域里的, 即, ret离开get作用域 就消失, 那么: 返回值的 就是这个ret
本身!!! - 否则, 这个
ret
, 离开get作用域后 依然存在, 那么, 在返回时: 不会返回ret本身, 而是会 构造一个(临时对象) 返回出去!!!
实例
ST Get(){ return ST();}
ST Gett(){ return Get();}
ST Gettt(){ return Gett();}
调用Gettt();
时, 只会调用1次 ST的构造 (对应上面ST();)
!!!
因为: 当 返回值是: 局部变量 时, 返回的就是这个对象本身.