• 做一个幸福的人,读书,旅行,努力工作,关心身体和心情。
  • 不管有没有人爱,也要努力做一个可爱的人。不埋怨谁,不嘲笑谁,也不羡慕谁,阳光下灿烂,风雨中奔跑,做自己的梦,走自己的路。

C++中的临时对象

C/C++ lcq 3年前 (2015-07-18) 723次浏览 0个评论

引子:请看我的前面的一篇博文提到的一个简单问题。就是一个函数void print(string &msg = string("Hello World")){cout << msg << endl;};会报错的问题(注意,在Visual Studio 2013中是正常的呀,只有在MinGW中才会报错)。基于此,我在寻找资料的过程中,看到了一些关于C++临时对象的一些讲述,自己做个笔记。

C++中的临时对象是你看不见摸不着但确实是有编译器产生存在的。大家一定记得以下的例子:

然后,你可能会说,temp是临时变量,错了。temp不是临时变量,是个局部变量而已。反正认准,临时对象你在代码中是看不到的。

C++有下面几种情况会产生临时对象。

1、类型的强制转换。

还是以上面的print函数为说明对象。假设你写的print函数声明实现如下:

如果你这样调用:

那么一点问题都没有。但是你要是如果这么调用:

编译器立马会报如下错误:error: invalid initialization of non-const reference of type 'std::string& {aka std::basic_string<char>&}' from an rvalue of type 'const char*'。原谅我这个英语不好的孩纸,编译器大概告诉我们的是:不能将一个const char*类型的右值转换为一个非const类型的string引用。C++标准的规定:非常量的引用不能指向临时对象。但是这个临时对象是如何产生的呢。因为你调用print("Hello World");的时候,"Hello World"是一个const char *的常量,为了函数能够顺利执行,编译器他自动调用string的构造函数,利用"Hello World"构造一个string的临时对象。此时,我们也就能很容易理解“非常量的引用不能指向临时对象”这句话了,试想,如果编译器允许这么做了,那么也就是说编译器允许我对临时值string msg进行修改。如果我在print里面对msg进行了修改,那么,我传进来的"Hello World"还是"Hello World",这与我们的期望值是不一致的。因为对引用的修改就是对原来的修改。

基于此,如果你想让上面的print("Hello World")函数正确运行,也很简单,将void print(string &msg)改为void print(const string &msg)即可。

2、按值传递。

看下面一段代码即可:

执行结果如下:

前面两行,很显然,是调用构造函数的时候产生的。主要看第3行,为什么调用了类的拷贝函数呢?那是因为在调用函数sumAge的时候将S2以传值的方式传入的。为什么要创建一个临时对象,很显然,是为了在sumAge函数里面对s2的任何修改,都不会对外面的s2产生任何的副作用。编译器大概对传入的参数s2做了如下步骤:

3、按值返回。

依然使用上面的代码,添加一个函数如下:

然后在main函数里面调用:

输出的结果如下:

很显然,第一行是因为getStudent()函数调用Student s(age);产生的,而第二行,是因为产生了一个临时对象的拷贝。具体过程编译器大概可能是这样的:

所以,如果你将Student getStudent(int age)改为Student& getStudent(int age),将不会有第二行的输出。当然,这不是正确的做法,因为你返回一个局部变量的引用是很危险的,因为函数结束的时候,这个局部变量已经被析构了。

好了,总结了一些产生临时对象的地方。那对我们的编程有什么意义呢。因为临时对象的产生伴随着对象的构造与析构。而函数的构造与析构是需要花费时间的。所以,知道哪些地方会产生临时对象,同时避免产生临时对象,对函数运行的效率是有一定的积极意义的。


参考博文:

1、临时对象不能被绑定到非const引用参数上====》扩展到临时对象问题

2、编译器的差异:临时对象做实参的可能编译不过

3、小问题大思考之C++临时对象

4、C++中的临时对象

5、C++中的临时对象

6、C++临时对象(1)

7、C++临时对象(2)

8、C++临时对象的来源


乐趣公园 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明C++中的临时对象
喜欢 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址