首先,永远不要返回局部变量的引用。因为局部变量在函数返回时被回收,即这个变量不存在了,所以以后对这个变量的引用都是无意义的,结果是不可预知的,程序很可能会崩溃。因此,也就不解释这种情形的结果了。
由于静态变量的声明周期直到程序结束,所以返回静态变量的引用是有意义的,而且安全的。下面解释返回静态变量的引用的情形:
#include
using namespace std;
int& f(){
static int b = 40;
return b;
}
int main(){
int& e = f();// e为b的别名
int e2 = f();// e2为b的拷贝
cout << "e's address = " << &e << "e's value=" << e << endl;
cout << "e2's address = " << &e2 << "e2's value=" << e2 << endl;
cout << "f()'s address = " << &f() << "f()'s value=" << f() << endl;
// 因为e为b的别名,第一个和第三个输出一样
f() = 10;// 修改b的值
cout << "e's address = " << &e << "e's value=" << e << endl;
cout << "e2's address = " << &e2 << "e2's value=" << e2 << endl;
cout << "f()'s address = " << &f() << "f()'s value=" << f() << endl;
// 因为e2为b的拷贝,不受影响
return 0;
}
指的是你返回一个指向局部变量的引用,包括参数。
b是int类型,auto在c++中是一个废弃的关键字,不过在c++11中被重新启用,用来自动推导类型。e是一个引用类型,即可以想象成就是被引用的对象,所以当你取e的地址时,其实获得的是被引用的对象地址。由于你的e引用的是一个局部变量,也就是栈上的变量,因为栈的起始地址一般都会随机变化,所以你会得到不一样的结果。随机变化的原因是为了防止某些类型的攻击,提高程序安全性。
c++中不存在static类型一说,static是用来指示变量的生命周期类型,即静态生命周期。我想你是想说b是static int。当为static int时,程序启动时就会将b初始化为40,此时一直持续到程序结束,所以此时返回引用是合法,因为编译器保证,该变量生命周期会持续整个程序运行期间。
e2 = f();
这里返回引用,而e2不是引用,所以会进行拷贝初始化,所以e2和f()返回的引用是两个对象。e2为40。
f()=10;
这里由于返回引用,而引用指向static int b,所以会对b进行修改,于是b变为10。
e2是main的局部变量,e是引用,f()返回值是引用,此时e等价于f()。当取地址时,e2的地址将不会等于e的地址,因为他们是两个对象,两个对象的地址必然不同(除了一个类的子对象)。这里e2是局部变量,所以分配在栈上,而e,f()指向的是静态变量,所以分配在全局内存中。
引用是绑定内存,意思是一个引用会锁定程序的地址空间中某一地址,地址是常量,只有该地址对应的内存单元的内容可以变化
这个问题上,先说明一个原则:函数不要返回一个临时变量的引用。因为临时变量在栈区,函数结束时它的地址空间要回收再用,所以接下来这个地址的内容变成不可控。对于auto b的情况,就触犯了这个原则,没有研究的意义。至于为什么单步执行和一次执行结果不一样,可能是VC在不同的调试模式下对地址空间的使用不一样吧。
b为static的时候,b处于程序的数据段,不在是栈区,因为b不是临时变量了,所以对b进行赋值后,它的状态会保留至函数结束。
f()=10是赋值,b是auto时,赋值给栈内存;b是static时,赋值给数据段内存。