对三,王炸:

赋值的本质,是将变量传递给一个匿名临时变量,之后再传递给另一个变量。


  •  匿名临时对象:
  1. #include <iostream>
  2. using namespace std;
  3.  
  4. class A {
  5. public:
  6. A() {
  7. cout << "构造函数:" << this << endl;
  8. }
  9. A(const A &a) {
  10. cout << "拷贝构造函数:" << this << endl;
  11. }
  12. ~A() {
  13. cout << "析构函数:" << this << endl;
  14. }
  15. };
  16.  
  17. A f() {
  18. A a;
  19. return a;
  20. }
  21. int main() {
  22. A a = f();
  23. return ;
  24. }

首先要知道赋值的时候回调用拷贝构造函数,初始化的时候调用构造函数:

执行 return a; 产生了匿名临时对象 F903,在给a(外面的)的赋值之前,销毁局部对象F803,F903赋值给了外面的a,程序执行结束时销毁。

A()用来创建匿名对象,理论上这也是应该调用拷贝构造函数的,但事实上,编译器会对此进行优化,变成A a;

 那么怎样能避免产生临时对象呢?

直接赋值是不可避免的,但是作为函数返回值时是可以避免的:

当返回类型为引用是,在内存中不产生返回值的副本(注意:不能返回局部变量的引用,局部变量会在函数之前销毁。)

  1. 对于这个例子,左边的return ,实际上是调用拷贝构造函数把该对象的值拷入临时对象,再进行return
    return完毕临时对象即刻销毁。对于一般变量亦是如此,只是不调用构造函数。

  1. 注意:
  • 不要返回函数内部new分配的内存的引用:

正常写法,无内存泄漏。

被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,显然new生成的这块内存将无法释放。

(和上面说的不矛盾,这里直接把*s返回了,不再需要额外的一个临时变量了,但是外面的string s; 已经在栈中分配内存了。)

想要释放掉这片内存,只能这样:

  1. 所以说,并不是说返回函数内存new分配的内存的引用或指针是非法的,只是说如果要返回,必须要十分注意,因为很有可能造成内存泄露。
    所以一般不提倡返回函数内存new分配的内存的引用或指针。

  •  强制类型转化:

C++属于强类型语言,只要类型不一样,就不能赋值。

但是这里是可以赋值当场打脸,也是因为出现了一个匿名临时对象作为隐式转换的过渡桥梁。

    

注意第二张图:

这里并不是&b开辟了新的空间,引用的就是转换的临时变量

(int &b = a;是报错的)可见临时变量的常量性,const才能引用。

下面这样的隐式转换看似好像是错的。

  1. #include <iostream>
  2. using namespace std;
  3.  
  4. class A {
  5.  
  6. public:
  7. int x;
  8. A(int num) {
  9. cout << "构造函数:" << this << endl;
  10. x = num;
  11. }
  12. A(const A &a) {
  13. cout << "拷贝构造函数:" << this << endl;
  14. }
  15. ~A() {
  16. cout << "析构函数:" << this << endl;
  17. }
  18. };
  19.  
  20. int main() {
  21. A a = ;
  22. cout << a.x << endl;
  23. return ;
  24. }

两个不同类型能否进行赋值操作,在于能否找到一个中间桥梁,这里的赋值寻找到了构造函数A(int num){};(重载 ‘=’ 运算符也是可以实现的) 所以可以成功,并且a成功实例化。

在构造函数前加上explicit关键字,则禁止 类似这样 不应该允许的经过转换构造函数进行的隐式转换的发生。

加上一个operator int(),反过来也是可以实现的:


C/C++——赋值理解(匿名临时对象)的更多相关文章

  1. C++中的一类临时对象

    类名(参数名)这样的对象是临时对象,不能取地址,不能被引用,不过可以给同类型的其他对象赋值,该临时对象定以后可以进行一次操作,然后立即销毁. 当我们定义一个对象以后并不想立即给它赋初值,而是以后给它赋 ...

  2. 【编程篇】C++11系列之——临时对象分析

    /*C++中返回一个对象时的实现及传说中的右值——临时对象*/ 如下代码: /**********************************************/ class CStuden ...

  3. 与临时对象的斗争(上)ZZ

    C++ 是一门以效率见长的语言(虽然近来越来越多的人“不齿”谈及效率,我深以为不然,在某一次的程序编写中不对效率锱铢必较并不意味意味着我们就不应该追求更多的更好的做法).总之吧,相比起其它语言,程序员 ...

  4. 认识C++中的临时对象temporary object 分类: C/C++ 2015-05-11 23:20 137人阅读 评论(0) 收藏

    C++中临时对象又称无名对象.临时对象主要出现在如下场景. 1.建立一个没有命名的非堆(non-heap)对象,也就是无名对象时,会产生临时对象. Integer inte= Integer(5); ...

  5. C++中临时对象的学习笔记

    http://www.cppblog.com/besterChen/category/9573.html 所属分类: C/C++/STL/boost  在函数调用的时候,无论是参数为对象还是返回一个对 ...

  6. C++ 临时对象

    1.什么是临时对象? swap方法中,常常定义一个temp对象,这个temp对象不是临时对象,而是局部对象.这里所说的临时对象是不可见的,在原代码中是看不到的. 2.为什么会产生临时对象? a.客户期 ...

  7. 【M19】了解临时对象的来源

    1.首先,确认什么是临时对象.在swap方法中,建立一个对象temp,程序员往往把temp称为临时对象.实际上,temp是个局部对象.C++中所谓的临时对象是不可见的,产生一个non-heap对象,并 ...

  8. [转] C++中临时对象及返回值优化

    http://www.cnblogs.com/xkfz007/articles/2506022.html 什么是临时对象? C++真正的临时对象是不可见的匿名对象,不会出现在你的源码中,但是程序在运行 ...

  9. C++ —— 非常量引用不能指向临时对象

    目录 举例 分析 解决 1.举例 非常量引用 指向 临时对象 —— 即:将 临时对象 传递给 非常量引用类型. 如以下情况就会出现: 实现实数Rational类,实数可以使用+号相加,运算的结果要可以 ...

随机推荐

  1. 后台数据校验-BeanCheck

    package com.ldf.domain; import java.text.ParseException; public class UserCheck { //从表单获取的数据 private ...

  2. 武汉邀请赛 Key Logger 双向链表

    Key Logger Time Limit: 3000ms Case Time Limit: 3000ms Memory Limit: 65536KB   64-bit integer IO form ...

  3. MySQL三层逻辑架构

    MySQL的存储引擎架构将查询处理与数据的存储/提取相分离.下面是MySQL的逻辑架构图: 第一层负责连接管理.授权认证.安全等等. 每个客户端的连接都对应着服务器上的一个线程.服务器上维护了一个线程 ...

  4. BZOJ4516: [Sdoi2016]生成魔咒(后缀数组 set RMQ)

    题意 题目链接 Sol 毒瘤SDOI 终于有一道我会做的题啦qwq 首先,本质不同的子串的个数 $ = \frac{n(n + 1)}{2} - \sum height[i]$ 把原串翻转过来,每次就 ...

  5. float失效的情况

    前言:在最近的笔试中,两次碰到类似的问题,什么情况下float会失效?我目前知道的有2种: 1)display:none: 2)position:absolute.fixed. (1)display: ...

  6. Grunt入门学习之(2) -- Gruntfile的编写

    Gruntfile由以下几部分构成: "wrapper" 函数 项目与任务,目标配置 加载grunt插件和任务 自定义任务 1.wrapper函数(包装函数) 每一个 Gruntf ...

  7. PHP后台处理jQuery Ajax跨域请求问题 — xx was not called解决办法

    // 前台代码 $.ajax({ url: 'http://www.ushark.net/home/save_trial_apply', dataType: 'jsonp', processData: ...

  8. rabbitmq集群配置

    原文地址:http://www.360doc.com/content/14/0911/17/15077656_408713893.shtml 按照文章中的方式成功建立了两台机器的集群. 但文章中加入集 ...

  9. C# winfrom DataGridView用法

    DataGridView列的宽度自动调整,可以使用DataGridView.AutoSizeColumnsMode属性实现. 下面的代码就是列的宽度根据Header和所有单元格的内容自动调整的. // ...

  10. Linux 系统网络问题处理集[包含VM处理]

    1.1. 新操作系统ping不同主机: 检查Linux服务器网段是否有etho的IP 查看/关闭防火墙 查看:service iptables status 关闭:service iptables s ...