读书人

函数返回值有关问题

发布时间: 2012-02-06 15:52:44 作者: rapoo

函数返回值问题
string fun()
{
return "some ";
}
///////
情况一
////
const char* c = fun().c_str();
//////
情况二
string& str = fun();
const char* c = str.c_str();

///实验结果
情况一
c中存 " "
情况二
c中存 "some "

why?


[解决办法]
利用临时变量,所有“奇怪”的现象都是可能的
你的两种情况都是不合法的
[解决办法]
情况一
////
const char* c = fun().c_str(); // fun返回的string是临时的,你访问c时他理论上已经不存在了,因此它的值可能被reset


情况二
string& str = fun();
const char* c = str.c_str();

fun返回的依然是临时的,可以看到 "some "与其是你认为的必然,你还不如认为它是一种凑巧,中间稍微加一点代码可能就变了


千万不要超出变量作用域访问、使用临时变量
[解决办法]
LS正解。
[解决办法]
"fun返回的依然是临时的,可以看到 "some "与其是你认为的必然,你还不如认为它是一种凑巧,中间稍微加一点代码可能就变了 "

这个不是凑巧,临时变量被绑定到一个引用上,会将该临时变量的生命周期延续到引用的生命周期内。
lz是不是用的vs2005来编译的?不明白为什么临时变量可以帮定到一个非const的引用上...


[解决办法]
所谓的延长生命期一说我从来没听说过
这种说法只在COM中有
C++对象是没有的

[解决办法]
如果不信,这样试试,我估计已经不能有aaa这个字符串了。不过我没有试过,理论应该如此

string func1()
{
return "aaa ";
}

const char * p;
void func2()
{
string & str = func1();
p = str.c_str();
}

void func4()
{
string a= "haha, my friend ";
cout < < a < <endl;
}
void func3()
{
func2();
func4();
cout < < p < < endl;
}

[解决办法]
lddLinan(粪青多了,社会自然和谐了) :你说的这个在C#中也有,但是C++肯定没有延长生命期一说的
[解决办法]
如果你来不是为问问题而是为了宣传你网站,咱可不愿意去
要让人去,得想好招,不能通过诱导方式来做
[解决办法]
lddLinan(粪青多了,社会自然和谐了) :你说的这个在C#中也有,但是C++肯定没有延长生命期一说的

说话可要负责任,去翻翻标准吧,别动不动就高屋建瓴。
大家可以参考
class C {
/ / ...
public :
C();
C(int );
friend C operator +( const C&, const C&);
~C();
};

C obj1 ;
const C& cr = C (16)+ C (23);
C obj2 ;
the expression C(16)+C(23) creates three temporaries. A first temporary T1 to hold the result of the expression C(16),
a second temporary T2 to hold the result of the expression C(23), and a third temporary T3 to hold the result of the
addition of these two expressions. The temporary T3 is then bound to the reference cr. It is unspecified whether T1 or
T2 is created first. On an implementation where T1 is created before T2, it is guaranteed that T2 is destroyed before T1.
The temporaries T1 and T2 are bound to the reference parameters of operator+; these temporaries are destroyed at the
end of the full expression containing the call to operator+. The temporary T3 bound to the reference cr is destroyed
at the end of cr’s lifetime, that is, at the end of the program. In addition, the order in which T3 is destroyed takes into
account the destruction order of other objects with static storage duration. That is, because obj1 is constructed before


T3, and T3 is constructed before obj2, it is guaranteed that obj2 is destroyed before T3, and that T3 is destroyed before
obj1. —end example ]

[解决办法]
“So the rule is that a temporary bound to a reference

persists for the lifetime of the reference initialized or until the end of the scope in which the temporary is created, whichever comes first”

这句话本来是想对标准里的一段拗口的话的概括,但实际上是不正确的,还盼大家都翻番标准
[解决办法]
标准里有这样一段话:
A temporary bound to a reference parameter in a function call (5.2.2) persists until
the completion of the full expression containing the call.

在这种情况下,引用的lifetime结束在函数结束点,但临时变量生命的结束要晚一些,在调用函数表达式结束的点,“whichever comes first”在这种情况下是不正确的,这句话只考虑了临时变量先于引用离开总用域的大多数情况。
[解决办法]
讨厌得广告,坚决不去

[解决办法]
不过经过验证,临时变量确实不会提前析构

不过这样的代码写出来确实垃圾是吧?让人不迷糊是写代码人的责任
[解决办法]
各位都很熟悉标准啊
int ai()
{
return 1;
}

....

int& i = ai(); //为何编译通不过?
[解决办法]
参考这句话
“lz是不是用的vs2005来编译的?不明白为什么临时变量可以帮定到一个非const的引用上...”
[解决办法]
qiang!
[解决办法]
你有函数如下:

string fun()
{
return "some ";//这儿调用string的一个转换构造函数构造一个临时对象!
}

如上注释,临时对象用以保存fun的返回值,该临时对象的字符串是 "some "。

接下来在程序中:

///////情况一:
const char* c = fun().c_str();

根据C++标准对临时对象生命期的规定一,上述临时对象必须在 "fun().cstr() "执行(表达式求值)完毕后,才可被摧毁!,所以类似C++伪码是:

string _strTemp = fun();//_strTemp是临时匿名对象!
const char* _cTemp = _strTemp.cstr();
_strTemp.~string();//临时对象在此析构!
const char* c = _cTemp;

注意,临时对象析构的时候,在它的析构函数中调用了delete[]删除了字符缓存区!所以此时以c指针退化成了一个void*,因此你的情况一是:

c值的内容不可预见,在此例中是 " ",即: cout < < c;//将输出 " "!


情况二
string& str = fun();
const char* c = str.c_str();

在此例中fun同样是返回一个临时对象,不同的是这次是以接受返回值的string引用绑定这个临时对象,这样一来,根据C++标准对临时对象生命期的规定二,fun产生的那个临时对象必须要等绑定它的引用str的生命期结束,它才可以被析构!

这样,只要c与str的生命期同步,c将有效的指向那个临时对象的字符缓存区,所以你的情况之二是:

c中存 "some ",我大胆的推测,你的程序测试代码应该类似如下:

int main()
{
///////情况一////
const char* c = fun().c_str();
cout < < c < < endl;//输出 " "!

//////情况二
string& str = fun();
c = str.c_str();
cout < < c < < endl;//c与str生命期同步,c因此总是指向有效的字符buffer! "some "

return 0;//str、c以及那个临时对象在此析构!
}



[解决办法]
ls
分析的很透彻!!!!!!!!!!
[解决办法]
各位都很熟悉标准啊
int ai()
{
return 1;
}

....

int& i = ai(); //为何编译通不过?
==========================================
参考这句话
“lz是不是用的vs2005来编译的?不明白为什么临时变量可以帮定到一个非const的引用上...”
==============================================

string& str = fun();
这里string&也不是const引用啊!!!!


------解决方案--------------------


学习。
[解决办法]
fish6344分析的不错,写了个类测试了一下:

class MyString
{
char *m_szData;
public:
MyString(){ m_szData = NULL; }

MyString(const char *szData)
{
m_szData = new char[ strlen(szData) + 1 ];
strcpy( m_szData, szData );

printf( "MyString(const char *szData)(%s)\n ", m_szData );
}

~MyString()
{
printf( "~MyString(%s)\n ", m_szData );

delete m_szData;
m_szData = NULL;
}

const char *c_str(){ return (const char*)m_szData; }
};

MyString fun()
{
return "some ";
}

int main(int argc, char* argv[])
{
const char *c1 = fun().c_str();
std::cout < < "c = " < < c1 < < std::endl;

MyString& str = fun();
const char *c = str.c_str();
std::cout < < "c = " < < c < < std::endl;

return 0;
}
[解决办法]
致yhmhappy2006(Nathan)朋友:

你的问题很简单:

int ai()
{
return 1;
}

....

int& i = ai(); //为何编译通不过?

是因为 '1 '是一个常量型对象,而你以一个非常型引用指向常型的临时对象,显然违反了语言‘不能以非常型引用绑定常量对象 '的规则,故不能通过编译!

另外,你说:

string& str = fun();
这里string&也不是const引用啊!!!!

虽然 "some "是常型字符串,但是在被转换成string临时对象的时候,是这个常字符串被复制到了该临时对象的buffer!该buffer不是常量字符数组,该临时对象也不是常型对象,所以,

string& str = fun();
这里string&也不是const引用啊!!!!

是非常自然的事情,不应有疑问的!

致 erwin1984(erwin) ( )朋友:我也和你同样写了一个类作实验,和你差不多,如下:

long _lCount;//析构计数器;

class zstring
{
char* _pStr;
public:
zstring(const char* p = " ")
{
long _lMax = sizeof(p);

if(_lMax)
{
_pStr = new char[_lMax + 1];
strcpy(_pStr,p);
}
}

~zstring(void)
{
++_lCount;//析构计数
delete []_pStr;

cout < < "析构,计数值: " < < _lCount < < endl;
}

const char* zc_str()
{
return _pStr;
}
};


zstring zfun()
{
return "Some ";
}


int main()
{
{//增加一级堆栈,以利观察:
///////情况一////
const char* zc = zfun().zc_str();
cout < < zc < < endl;//输出不确定值!在该语句执行前可看到临时对象的析构!

//////情况二
zstring& zstr = zfun();
zc = zstr.zc_str();
cout < < zc < < endl; //输出 "Some "!

}//zc、zstr、及那个临时对象在此析构!

_PAUSE;
return 0;
}

该程序行为良好,完全支持我先前的阐述!


[解决办法]
临时变量,好像不支持这样做
[解决办法]
int ai()
{
return 1;
}

怎么没有临时变量产生啊?
[解决办法]
书上说看一个类型设计的合不合理将它与int的行为比较一下就知道了,这里string和int的行为不一样?

读书人网 >C++

热点推荐