15 临时对象

1 问题

  • 下面的程序输出什么?为什么?

    class Test
    {
        int mi;
    public:
        Test(int i) {
            mi = i;
        }
        Test() {
            Test(0);  // 直接调用构造函数:产生一个临时对象,等价于空语句
        }
        void print() {
            printf("mi = %d\n",mi);
        }
    };
    
    int main()
    {
        Test t;
        t.print();  // mi = -1080889604
        
        return 0;
    }
    
  • 程序分析

    • 程序的意图

      • Test() 中以 0 作为参数调用 Test(int i)
      • 将成员变量 mi 的初始值设为 0
    • 运行的结果

      • 成员变量 mi 的值为随机值
    • 哪个地方出了问题?

  • 【问题】构造函数是一个特殊的函数

    • 是否可以直接调用
    • 是否可以在构造函数中调用构造函数?
    • 直接调用构造函数的行为是什么?
  • 分析

    • 直接调用构造函数将产生一个临时对象
    • 临时对象的生命周期只有一条语句的时间
    • 临时对象的作用域只在一条语句中
    • 临时对象是 C++ 中值得警惕的灰色地带

2 解决方案

  • Demo

    #include <stdio.h>
    
    class Test {
        int mi;
        
        void init(int i) {
            mi = i;
        }
    public:
        Test(int i) {
            init(i);
        }
        Test() {
            init(0);
        }
        void print() {
            printf("mi = %d\n", mi);
        }
    };
    
    
    int main()
    {
        Test t;
        
        t.print();   // mi = 0
    
        return 0;
    }
    
  • 编译器的行为

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

    • Demo

      #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 = 0;
          }
          int print() {
              printf("mi = %d\n", mi);
          }
          ~Test() {
              printf("~Test()\n");
          }
      };
      
      Test func()
      {
          return Test(20);  // 函数返回一个临时对象
      }
      
      int main()
      {
          Test t = Test(10); // 1.生成临时对象,调用构造函数 2.利用临时对象初始化一个对象,调用拷贝构造函数  => 编译器优化 <=> Test t = 10; => 只调用一次构造函数
          Test tt = func();  // 1.生成临时对象,调用构造函数 2.利用函数返回的临时对象初始化一个对象,调用拷贝构造函数 => 编译器优化 <=> Test tt = Test(20); <=> Test tt = 20; =>只调用一次构造函数
          
          t.print();
          tt.print();
          
          return 0;
      }
      
    • 编译运行

      Test(int i) : 10
      Test(int i) : 20
      mi = 10
      mi = 20
      ~Test()
      ~Test()
      
posted @ 2020-09-23 19:02  nxgy  阅读(100)  评论(0编辑  收藏  举报