1,临时对象神秘在于不知不觉就请入程序当中,并且给程序带来了一定的问题;

2,下面的程序输出什么?为什么?

 #include <stdio.h>

 class Test
{
int mi;
public:
Test(int i)
{
mi = i;
} Test() // 这里程序作者想要代码复用,直接调用已经构造好的函数来完成没有参数的构造函数的函数体;
{
Test(); // 得到临时对象,没有名字,就意味着作用域只在这个语句,过了这个语句,就没法被访问到了;这里的语句在这里没有什么作用,等价于空的语句;
} void print()
{
printf("mi = %d\n", mi);
}
}; int main()
{
Test t; t.print(); // 期望 mi 为 0;但是结果却是随机值; return ;
}

3,程序意图:

1,在 Test() 中以 0 作为参数调用 Test(int i);

2,将成员变量 mi 的初始值设置为 0;

运行结果:

1,成员变量 mi 的值为随机值;

4,构造函数是一个特殊的函数:

1,是否可以直接调用?

1,给编译器主动调用的,但也可直接手工调用;

2,是否可以在构造函数中调用构造函数?

1,从编译器的编译结果来看在语法上合法;

3,直接调用构造函数的行为是什么?

1,直接调用构造函数将会产生一个临时对象;

1,是一个合法的 C++ 对象,生命期只有一条语句时间;

2,过了这个语句临时对象就会被自动析构而不复存在;

3,临时对象是没有名字的;

2,临时对象的生命周期只有一条语句;

3,临时对象的作用域只在一条语句中;

4,临时对象是 C++ 中值得警惕的灰色地带;

1,同 C 中的野指针一样必须警惕;

5,避免因代码复用调用构造函数而带来的临时对象的解决方案:

 #include <stdio.h>

 class Test {
int mi; void init(int i)
{
mi = i;
} public:
Test(int i)
{
init(i);
} Test()
{
init(); // 工程中代码复用方式
} void print() {
printf("mi = %d\n", mi);
}
}; int main()
{
Test t; t.print(); return ;
}

6,临时对象的测试:

 #include <stdio.h>

 class Test {
int mi; void init(int i)
{
mi = i;
} public:
Test(int i)
{
printf("Test(int i)\n");
init(i);
} Test()
{
printf("Test()\n");
init();
} void print() {
printf("mi = %d\n", mi);
} ~Test()
{
printf("~Test()\n");
}
}; int main()
{
printf("main begin1\n"); Test(); // 产生临时对象;打印 ==> Test() ~Test() Test(); // 产生临时对象;打印 ==> Test(int i) ~Test() printf("main end1\n"); printf("main begin2\n"); Test().print(); // 临时对象生成之后直接调用 print() 函数;这里可以通过编译,因为调用了构造函数之后呢就会产生临时对象了,通过合法的 C++ 对象加上点操作符来调用对应的成员函数是完全没有问题,完全合法的;产生临时对象;打印 ==> Test() mi = 0 ~Test()
Test().print(); //产生临时对象;打印 ==> Test(int i) mi = 10 ~Test() printf("main end2\n"); return ;
}

1,这里仅是教育需要,向大家介绍这个知识点,在以后工程开发中,万不可这样写代码,一定要去避免临时对象的产生和使用;

7,现代 C++ 编译器在不影响最终执行结果的前提下,会尽力减少临时对象的产生;

8,神秘的临时对象编程实验:

1,证明 C++ 编译器在极力的减少临时对象的产生;

 #include <stdio.h>

 class Test
{
int mi; public:
Test(int i)
{
printf("Test(int i) : %d\n", i);
mi = i;
} Test(const Test& t)
{
printf("Test(const Test& t) : %d\n", t.mi);
mi = t.mi;
} Test()
{
printf("Test()\n");
mi = ;
} int print()
{
printf("mi = %d\n", mi);
} ~Test()
{
printf("~Test()\n");
}
}; Test func()
{
return Test(); // 生成一个临时对象,函数调用结束后就立即销毁临时对象了
} int main()
{
/*
Test t(10); // 等价于 Test t = Test(10); 于是可解读为:1,生成临时对象 2,用临时对象初始化即将生成的 t 对象,于是必然涉及到调用拷贝构造函数,但是编译器打印的结果为 Test(int i) : 10 mi = 10 ~Test()根本没有任何拷贝构造函数的迹象产生;编译器根本没有像我们解读的上述的两个步骤执行;这是因为现代的 C++ 编译器都会尽量的减少临时对象的产生;从执行结果来看,上面的分析是没有任何错误的,只是上面的还要再调用一次拷贝构造函数,通过上面的分析,即便结果没有任何的变化,但是效率降低了,因此在这个地方 C++ 编译器为了杜绝临时对象的产生,直接将Test t = Test(10) 等价成为了 Test t = 10,这样就杜绝了临时对象的产生;杜绝临时对象的产生是因为其往往会带来性能上面的题,先生成一个临时对象调用了一次构造函数,再将临时对象通过拷贝构造函数来初始化 t,也就是说调用了两次构造函数,如果说我们极力的减少临时对象的产生,那么通过上述第二个方式等价 ,这样调用一次构造函数就可以了,少调用了一次拷贝构造函数,性能就提升了;在这个地方从性能上我们没有多大体会,但在实际的工程 开发中,构造函数里面所做的初始化工作往往是纷繁复杂的,比方说有些类的对象在初始化的时候,在调用构造函数的时候很可能打开外部设备,对设备进行初始设置等等,如果这个时候多了一次构造函数的调用,时间就消耗了;为什么要这样呢?因为 C++ 天生继承了 C 的特性,C 的一个最大特性就是高效,所以 C++ 的一个特性也是要极力的做到高效,该省掉临时对象的地方,就该省掉;
*/
Test t = Test(); // ==> Test t = 10; t.print(); Test tt = func(); // ==> Test tt = Test(20); ==> Test tt = 20; fun() 返回一个临时对象,到达了赋值符号右侧,此时临时对象里面的值会初始化 t 对象;当代的 C++ 编译器,在不影响最终结果的情况下,会极力的减少临时对象的产生; tt.print(); // 打印 mi = 20; return ;
}

9,小结:

1,直接调用构造函数将产生一个临时对象;

2,临时对象是性能的瓶颈,也是 bug 的来源之一;;

1,C++ 中除了野指针,还有临时对象;

2,工作中,如果出现了奇怪的问题,要从这两个方面考虑;

3,现代 C++ 编译器会尽力避开临时对象;

1,避开的前提是不影响最终的执行结果;

4,实际工程开发中需要人为的避开临时对象;

1,避免调用构造函数来初始化;

2,设计函数不要引入像 fun() 函数中的临时对象;

C++中的临时对象的更多相关文章

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

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

  2. 二十一、C++中的临时对象

    思考: 构造函数是一个特殊的函数 是否可以直接调用? 是否可以在构造函数中调用构造函数? 直接调用构造函数的行为是什么? 答: 直接调用构造函数将产生一个临时对象 临时对象的生命周期只有一条语句的时间 ...

  3. 从汇编看c++中临时对象的析构时机

    http://www.cnblogs.com/chaoguo1234/archive/2013/05/12/3074425.html c++中,临时对象一旦不需要,就会调用析构函数,释放其占有的资源: ...

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

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

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

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

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

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

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

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

  8. struts2中,OGNL访问值栈的时候查找的顺序是什么?请排序:模型对象、临时对象、固定名称的对象、Action对象

    struts2中,OGNL访问值栈的时候查找的顺序是什么?请排序:模型对象.临时对象.固定名称的对象.Action对象 解答:struts2的值栈排列顺序为:1).临时对象:2).模型对象:3).Ac ...

  9. 转:C++中临时对象及返回值优化

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

随机推荐

  1. spring(六):spring中AOP的基本使用

    AOP:面向切面编程[底层使用动态代理实现],就是在运行期间动态的将某段代码切入到方法的指定位置进行运行的编程方式 基本使用 使用AOP功能需要引入spring的aop以及aspects相关包 < ...

  2. linux性能分析工具Procs

  3. [数论]原根与指标,BSGS

    刚学了这方面的知识,总结一下.推荐学习数论方面的知识还是看书学习,蒟蒻看的是<初等数论>学的. 这里也推荐几个总结性质的博客,学习大佬的代码和习题. 原根:https://blog.csd ...

  4. 再谈lmbench

    摸了一轮ltp-ddt 再回头来看lmbench bandwidth & latency合集小王子 用起来确实方便. 只是官网显示的用法是: Go to the top directory, ...

  5. mongodb 面试题

    mongodb 面试题总结 1 nosql和关系型数据库的区别 NoSQL是非关系型数据库,NoSQL = Not Only SQL. 关系型数据库采用的结构化的数据,NoSQL采用的是键值对的方式存 ...

  6. USACO2008 Jan 电话网络

    Time Limit: 10 Sec Memory Limit: 162 MB Description Farmer John决定为他的所有奶牛都配备手机,以此鼓励她们互相交流.不过,为此FJ必须在奶 ...

  7. spring+springMVC+mybatis框架整合——配置文件说明

    如下图 web.xml配置说明: spring配置文件说明-1: spring配置文件说明-2: spring配置助记:  扫注(base) 读配(loc) 数据源(和comb(使用c3p0数据源)) ...

  8. sql语句中取整数和小数部分

    sql 取整数去小数点 ,) ' Sql截取浮点小数位数,不四舍五入 ,) 结果:551.24 ,) 结果:551.23 第一个2表示截取2位 第二个0,1分别表示0是四舍五入,0以外是截取 如何分别 ...

  9. LOJ 3090 「BJOI2019」勘破神机——斯特林数+递推式求通项+扩域

    题目:https://loj.ac/problem/3090 题解:https://www.luogu.org/blog/rqy/solution-p5320 1.用斯特林数把下降幂化为普通的幂次求和 ...

  10. [CSP-S模拟测试]:阴阳(容斥+计数+递推)

    题目传送门(内部题16) 输入格式 第一行两个整数$n$和$m$,代表网格的大小.接下来$n$行每行一个长度为$m$的字符串,每个字符若为$W$代表这个格子必须为阳,若为$B$代表必须为阴,若为$?$ ...