1.函数的调用执行过程
一个C++程序经过编译以后生成可执行的代码,形成后缀为.exe的文件,存放在外存储器中。当程序启动时,首先从外存将程序代码装载到内存的代码区,然后从入口地址(main()函数的起始处)开始执行。程序在执行过程中,如果遇到对其它函数的调用,则暂停当前函数的执行,保存下一条指令的地址(即返回地址,作为从子函数返回后继续执行的入口点),并保存现场,然后转到子函数的入口地址,执行子函数。当遇到return语句或者子函数结束时,则恢复先前保存的现场,并从先前保存的返回地址开始继续执行。
2.返回非引用的类型
函数的返回值用于初始化在调用函数处创建的临时对象。在求解表达式时,如果需要在一个地方存储其运算结果,编译器会创建一个没有命名的对象,这就是临时对象。
用函数返回值初始化临时对象与用实参初始化形参的方法是一样的。如果返回类型不是引用,在调用函数的地方会将函数返回值复制给临时对象。当函数返回非引用类型时,其返回值既可以是局部对象,也可以是求解表达式的结果。
3返回引用
当函数返回引用类型时,没有复制返回值。相反,返回的是对象本身。
//find shorter of two strings
const string &shorterString(const string &s1, const string&s2) //使用引用的最大好处是可以避免数据的复制
{
return s1.size()<s2.size()?s1:s2;
}
形参和返回类型都是指向const string 对象的引用,调用函数和返回结果时,都没有复制这些string对象。
理解返回引用至关重要的是:千万不能返回局部变量的引用。
当函数执行完毕时,将释放分配给局部对象的存储空间,此时,局部对象的引用就会指向不确定的内存。
//disaster :function returns a reference to a local object const string &manip(const string& s)
const string &manip(const string & s)
{
string ret =s;
//transform ret in some way
return ret;//wrong:returning a reference to a local object
}
这个函数会在运行时出错,因为它返回了局部对象的引用.当函数执行完毕时,字符串ret占用的存储空间被释放,函数返回值指向了对于这个程序来说不再有效的内存空间。
确保返回引用安全的一个好方法是:请自问,这个引用指向哪个在此之前存在的对象。
4.引用返回左值
返回引用的函数返回一个左值.因此,这样的函数可用于任何要求使用左值的地方:
char &get_val(string &str,string::size_type ix)
{
retunr str[ix];
}
int main()
{
string s ("a value");
cout<<s<<endl;
get_val(s,0)='A';//change s[0] to A
cout<<s<<endl;//prints A value
return 0;
}
给函数的返回值赋值可能是让人惊讶。由于函数的返回值是一个引用,因此这是正确的,该引用就是返回元素的同义词。
如果不希望引用返回值被修改 ,返回值应该声明为const
const char &get_val()
千万不要返回指向局部对象的指针。特别的,函数也可以返回指针类型,和返回局部对象的引用一样,返回指向局部对象的指针也是错误的,一旦函数结束,局部对象被释放,返回的指针就变成了指向不再存在对象的悬垂指针。