漫步云端

移动开发(Android、iPhone、Windows Mobile) | JAVA | C | C++ | .net | Objective C | 微软企业开发技术 | 嵌入式系统设计与开发
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

C++ 返回值注意事项

Posted on 2010-12-15 22:36  charley_yang  阅读(3738)  评论(1编辑  收藏  举报

一、缺省情况下,函数的返回值是按值传递的

这意味着得到控制权的函数将接收返回语句中指定的表达式的拷贝,例如:            

Matrix grow( Matrix* p ) {
    Matrix val;
 
     // ...
     return val;
}
grow()把存储在 val 中的值的拷贝返回到调用函数,但调用函数不能用任何方式修改val 。

 

二、该缺省行为可以被改变,一个函数可以被声明为返回一个指针或一个引用

当函数返回一个引用时,调用函数接收 val 的左值,即调用函数可以修改 val 或取它的地址。grow()可以如下声明返回一个引用: 
Matrix& grow( Matrix* p ) {
Matrix *res;
 
// 在动态存储中分配一个更大的 Matrix
// res 是指向新 Matrix 的指针
// 将*p 内容复制到*res
return *res;
}
如果返回值是一个大型类对象,用引用或指针返回类型比按值返回类对象效率要高得多,在某些情况下编译器自动将按值返回转换到按引用返回,该优化被称为命名返回值优化( named return value optimization )。

 

当声明一个返回引用的函数时,程序员应当知道下面两个易犯的错误: 

1.  返回一个指向局部对象的引用 局部对象的生命期随函数的结束而结束,在函数结束后,该引用变成未定义内存的别名,例如:
// 问题: 返回一个指向局部对象的引用
Matrix& add( Matrix &m1, Matrix &m2 )
{
Matrix result;
 
if ( m1.isZero() )
  return m2;
if ( m2.isZero() )
  return m1;
 
// 将两个 Matrix 对象的内容相加
// 喔! 返回之后 结果指向一个有问题的位置
return result;
}

在这种情况下,返回类型应该被声明为非引用类型,然后再在局部对象的生前拷贝局部变量 
Matrix add( ...

2.  函数返回一个左值 对返回值的任何修改都将改变被返回的实际对象,例:
#include <vector>
 
int &get_val( vector<int> &vi, int ix ) {
return vi[ix];
}
 
int ai[4] = { 0, 1, 2, 3 };
 
vector<int> vec( ai, ai+4 );  // 将 ai 的 4 个元素复制到 vec

int main() {
// 将 vec[0] 增加到 1
get_val( vec,0 )++;
 
// ...
}


为防止对引用返回值的无意修改,返回值应该被声明为const
const int &get_val( ...