zoukankan      html  css  js  c++  java
  • 第23课 神秘的临时对象

    有趣的问题:

    我们在无参构造函数中调用带一个参数的构造函数。

    程序如下:

     1 #include <stdio.h>
     2 
     3 class Test {
     4     int mi;
     5 public:
     6     Test(int i) {
     7         mi = i;
     8     }
     9     Test() {
    10         Test(0);
    11     }
    12     void print() {
    13         printf("mi = %d
    ", mi);
    14     }
    15 };
    16 
    17 
    18 int main()
    19 {
    20     Test t;
    21     
    22     t.print();
    23 
    24     return 0;
    25 }

    运行结果如下:

    mi并没有打印出0,而是一个随机值。

    发生了什么呢?

    思考:

    构造函数可以直接手工调用。

    上面的程序第10行直接调用了构造函数产生了临时对象。它的生命期只有第10行这一条语句,过了这条语句就会被析构。

    而且这个临时对象没有名字,作用域也仅仅在第10行这条语句中。第10行这条语句等价于没有,也就是空语句,因为这个临时对象我们无法使用。

    我们在无参构造函数中调用有参构造函数的本意是代码复用,但是没有达到目的,在工程中,代码复用时,我们要在类中提供一个普通的init函数,这时就可以将公共代码写到这个函数中。

     临时对象示例:

    由临时对象直接调用成员函数:

    可以看到临时对象构造完之后立即调用了打印函数。

    工程中要避免临时对象的产生与使用。

    编译器的行为:

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

    示例如下:

     1 #include <stdio.h>
     2 
     3 class Test
     4 {
     5     int mi;
     6 public:
     7     Test(int i)
     8     {
     9         printf("Test(int i) : %d
    ", i);
    10         mi = i;
    11     }
    12     Test(const Test& t)
    13     {
    14         printf("Test(const Test& t) : %d
    ", t.mi);
    15         mi = t.mi;
    16     }
    17     Test()
    18     {
    19         printf("Test()
    ");
    20         mi = 0;
    21     }
    22     int print()
    23     {
    24         printf("mi = %d
    ", mi);
    25     }
    26     ~Test()
    27     {
    28         printf("~Test()
    ");
    29     }
    30 };
    31 
    32 Test func()
    33 {
    34     return Test(20);
    35 }
    36 
    37 int main()
    38 {
    39     Test t = Test(10); // ==> Test t = 10;
    40     Test tt = func();  // ==> Test tt = Test(20); ==> Test tt = 20;
    41     
    42     t.print();
    43     tt.print();
    44     
    45     return 0;
    46 }

    39行的Test t = 10和Test t = Test(10)的编译运行结果是一样的。

    Test t = Test(10)在我们的直觉判断会有以下两步,1、创建临时对象;2、用临时对象初始化t(调用拷贝构造函数)。

    但是程序执行结果并不是按照我们的直觉分析那样的,这就是因为编译器做了优化。编译器会尽力减少临时对象的产生。

    编译器将Test t = Test(10)等价成了Test t = 10的形式。

    临时对象的产生会带来性能上面问题。

    工程中的构造函数会非常复杂,调用一次构造函数耗时很长。

    上述程序的运行结果如下:

    32-35行返回临时对象,然后在40行用这个对象初始化tt,但是从打印结果可以看出,构造函数并不是按照我们想象的情形来调用的,我们想象的情形是先调用构造函数产生临时对象,然后调用拷贝构造函数初始化tt。运行结果没有调用拷贝构造函数。

    这也是因为编译器的优化,在不影响执行结果的前提下会极力的减少临时对象的产生。

    我们写程序也应该尽力的避开临时对象,例如程序写成Test t = 10,而不是Test t  = Test(10)。这样就可以保证在任何一款编译器下都不会产生临时对象。

    小结:

  • 相关阅读:
    消息摘要技术(MD5)
    编写JsonResult封装JSON返回值(模板参阅)
    JS面向对象编程(进阶理解)
    markdown常用语法教程
    Spring-MVC请求参数值和向页面传值
    Spring-MVC开发步骤(入门配置)
    Live Templates快捷键模板
    压力测试中java.net.BindException: Address already in use: connect
    jmeter初始化工作
    xshell配色
  • 原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9569753.html
Copyright © 2011-2022 走看看