标签:
结论:
(1)如果一个类的方法返回一个对象(某个类对象),在使用中均应该将此对象首先赋值给一个局部变量,之后再使用此局部变量。决不能以此临时变量为中间变量再调用其它的。
1,有关 QString::toStdString() 使用的一个细节问题
例子:
// 1 ,错误的,cStr的值为非法 QString str = "Hello, world!"; char *cStr = str.toStdString().c_str(); // 2,正确的用法 std::string sstr = str.toStdString(); char *cStr2 = sstr.c_str(); // 3,正确的用法
func(str.toStdString().c_str());
原因如下:
为了解释前两段代码执行效果的不同,我们需要检查 QString::toStdString()
的签名:
std::string QString::toStdString() const;
这个函数返回一个与这个 QString
内容相同的 std::string
对象。注意这个函数的返回值是一个对象。在 C++ 中,函数返回对象一般是类似下面的代码:
clazz foo() const
{
clazz c;
c.member = 0;
return c;
}
注意这里的返回对象,其实是一个临时对象。在上面代码中,虽然我们在函数体内创建了一个 clazz
的对象 c
,但返回的并不是“这个”对象,而是由 C++ 创建一个临时对象,再将这个临时对象返回。注意这里是“临时对象”,临时对象是有生命周期的。《C++ 程序设计语言》第 10 章中写道,“ 除非一个临时对象被约束到某个引用,或者被用于作为命名对象的初始化,否则它将在创建它的那个完整表达式结束时销毁 ”。所谓“完整表达式”,是指不是其它表达式的子表达式的表达式。简单来说,一个完整表达式的标识一般是一个分号。
这句看似绕口的话解释了之前所有的现象。在第一段代码中,由于函数返回一个临时变量,我们立即调用了这个临时对象的 c_str()
函数。这一切都没有问题。之后,完整表达式结束(遇到分号),而这个临时变量没有赋值给某个引用或用于给某个对象初始化,所以这个临时变量被立即销毁。由此对象获得的 c_str()
函数结果同样被销毁,因此发生段错误。
在第二段代码中,这个临时变量用于给 sstr
对象初始化,我们之后调用的是这个新的被初始化完成的对象的函数,也就是正常的。
第三段代码虽然也没有赋值给某个引用或用于给某个对象初始化,但在 str.toStdString().c_str()
语句结束后,表达式并没有结束,而是继续执行函数调用。直到函数调用返回,才遇到代表表达式结束的分号,此时临时变量才会销毁。而这时候我们已经成功执行了函数代码。所以一切都没有问题。
至此我们明白了这种看似奇怪的现象其实只是一个 C++ 语言的陷阱,甚至与 Qt 没有一点关系。同样类似的陷阱还可能发生在 QString::toUtf8()
、 QString::toAscii()
之类的函数身上。
10.4.10 临时对象
临时对象经常作为算术表达式的结果出现。如求值x*y+z的中间结果x*y就是临时对象,必须存在某个地方。
除非有一个临时对象被约束到某个引用或者被用于做命名对象的初始化,否则它将总在建立它的完整表达式结束时销毁。完整表达式是指不是其他表达式的子表达式的表达式。考虑如下函数,这是个常见的错误。
标签:
原文地址:http://www.cnblogs.com/txf1949/p/4303168.html