首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

[C/C++] 函数返回值与返回局部对象的引用

2013-09-06 
[C/C++高手进] 函数返回值与返回局部对象的引用!主要有2个问题:大家都知道一条规则:不能返回局部对象的引

[C/C++高手进] 函数返回值与返回局部对象的引用!
主要有2个问题:

大家都知道一条规则:不能返回局部对象的引用。
而且编译器一般也会提示“reference to local variable returned"!

假设定义了类Test:


Test& f()
{
    Test t;
    t.i=1;
    return t;
}

Test g()
{
    Test t;
    t.i=1;
    return t;
}
int main()
{
    Test t1=f(); //---(1)
    Test t2=g(); //---(2)
}

比较语句(1)和语句(2):
语句(1)在调用f()函数后其栈空间被释放,但数据仍在栈中,而且不会因其它因素而导致数据损坏,因为当前栈帧为main函数的,栈顶指针比返回引用对象t的地址要高!
语句(2)很简单,但实际情况与想像的不一样。

第1个问题
我的理解是:如果返回一个局部对象的引用,程序员能够确保不会对该引用的对象进行修改,只用来读取,那么即使是这种做法不好,也不会导致运行出错。同时,既然是只读应该返回const引用,这样就可以避免去修改引用的局部对象(当然,绕开编译器强行修改该对象除外)!

语句2,我通过汇编发现实际情况有点不同寻常。我不知道,编译器是否都做了优化,我是在LINUX X64 GCC下编译的。汇编代码的结果让我很吃惊:实际调用为:g(&t2);而函数g()变成了如下形式

void g(Test* t)
{
    t->i=1;
}

语句2比语句1效率更高!!
PS:从另一方面也可以验证:语句(1)会调用复制构造函数;而语句(2)不会!!

第2个问题
照样正常理解,语句2应该返回一个临时对象;如果返回临时对象,那么临时对象到底存放在栈的哪个位置(寄存器是不可能了,Test类大小大于8Bytes),g()函数栈都已经收回了,临时对象难道放在main函数栈中?

多谢!!
[解决办法]
语句1既然是错误的,C++标准称之为“未定义行为”,发生啥结果都是正常的。
不要浪费时间在讨论错误的东西有啥“正确”的结果。
[解决办法]
++

引用:
语句1既然是错误的,C++标准称之为“未定义行为”,发生啥结果都是正常的。
不要浪费时间在讨论错误的东西有啥“正确”的结果。

[解决办法]
第一个函数,是返回函数栈中的数据,返回瞬间可以该数据仍然有效,但不保证
第二个函数,编译器会将函数栈中的返回值数据拷贝到返回栈中
[解决办法]
数据在栈中可能没有立即擦除内存地址而已!
导致可以拿到有效数据的
[解决办法]
引用:
Quote: 引用:


语句1既然是错误的,C++标准称之为“未定义行为”,发生啥结果都是正常的。
不要浪费时间在讨论错误的东西有啥“正确”的结果。


好吧,我知道是“未定义行为”。
我其实想问的是在自己完全可控的条件下,能否保证程序的正确性!
这就像char不能保证移植性,因为不同编译器可能实现的有无符号数不一样;但我只要保证使用char的值始终在可ANSI打印字符范围内,而且不用参与算术运算,照样可以跨平台!但很明显,这种做法风险比较大!

其实,有些“未定义行为”是完全可控的,但要自己保证,因为稍有不慎就可能出现纰漏。

我试过了,返回局部对象的引用的情况并非全部可控,因为会调用复制构造函数,进而破坏先前栈的数据,比如保存rdi和rsi寄存器。

你前面的对char的可控 没触犯未定义行为 
用这个char 说明不了存在可控的未定义行为

另外不管实现为 有符号 还是无符号 
根据你做出的保证 可以保证使用char没有风险

[解决办法]
编译器可以优化掉一些无关紧要的拷贝构造
gcc直接优化掉了

典型的例子就是
string s = "aaaa";理论上是先执行一次带参数构造,再执行一次拷贝.但实际上就执行一次构造

热点排行