码迷,mamicode.com
首页 > 编程语言 > 详细

C++返回对象的问题(临时对象问题)

时间:2015-02-27 14:52:51      阅读:331      评论:0      收藏:0      [点我收藏+]

标签:

结论:

(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就是临时对象,必须存在某个地方。

      除非有一个临时对象被约束到某个引用或者被用于做命名对象的初始化,否则它将总在建立它的完整表达式结束时销毁。完整表达式是指不是其他表达式的子表达式的表达式。考虑如下函数,这是个常见的错误。

void f(string& s1, string& s2, string& s3)

{  const char* cs = (s1+s2).c_str(); //在完整表达式赋值结束后,临时变量被销毁,cs变成了野指针!  cout << cs; // 错误!

  if (strlen (cs =(s2+s3).c_str()) < 8 && cs[0] == ‘a‘)   
  {
    cout << cs; //错误,理由同上
 
  }
}

为了比避免这样的错误我们可以使用下面的方式。

void g(string& s1, string& s2, string& s3)

{
  cout << (s1+s2).c_str(); // 在完整表达式cout结束时临时对象销毁,故cout可以正确输出。
  string s = s2 + s3;
  if(s.length() < 8 && s[0] == ‘a‘)  

  {
    cout << s;
  }
}

也可以使用临时变量作为const引用或者命名对象的初始式,例如,
void h(string& s1, string& s2)

{
  const string& s = s1 + s2;
  string ss = s1 + s2;
  g(s, ss, s1);
}

这样的临时变量在他的引用或者命名变量离开作用域时销。毁。故临时变量是一种匿名的局部变量,返回局部变量的引用是错误的。临时变量不是左值变量,不能约束到非cosnt引用。

 

 

 

C++返回对象的问题(临时对象问题)

标签:

原文地址:http://www.cnblogs.com/txf1949/p/4303168.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!