zoukankan      html  css  js  c++  java
  • 二十一、C++中的临时对象

    思考:

    构造函数是一个特殊的函数

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

    答:

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

    临时对象的生命周期只有一条语句的时间

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

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

    #include <stdio.h>
    
    class Test {
        int mi;
    public:
        Test(int i) 
        {
            mi = i;
        }
        Test() 
        {
            Test(0);		
            // 调用Test(int i),得到了一个临时对象,生命周期只有这句话,过了之后临时对象就被析构,临时对象没有名字,作用域也只有这句话,过了之后,不能再被访问。这里的临时对象几乎就没有作用。这个0根本就没有设置到mi上
        }
        // 等价于
        Test(){
            
        };
        void print() {
            printf("mi = %d
    ", mi);
        }
    };
    
    
    int main()
    {
        Test t;
        
        t.print();
    
        return 0;
    }
    
    // 解决办法
    // 提供一个私有的init函数,做初始设置
    class Test {
        int mi;
        void init(int i)
        {
            mi = i;
        }
    public:
        Test(int i) {
            printf("Test(int i)
    ");
            init(i);
        }
    
        Test(){
            printf("Test()
    ");
            init(0);	// 调用的普通私有函数,不会产生临时对象
        };
        
        void print() {
            printf("mi = %d
    ", mi);
        }
        
        ~Test()
        {
            printf("~Test()
    ");
        }
    };
    
    
    
    int main()
    {
        printf("main begin
    ");
        
        Test();		// 直接调用构造函数,会产生一个临时对象
        Test(10);	// 产生临时对象
        
        printf("main end
    ")
    
        return 0;
    }
    
    /*结果
    main begin
    Test()
    ~Test()
    Test(int i)
    ~Test()
    */
    
    int main()
    {
        printf("main begin
    "); 
        Test().print();		// Test()结果是一个临时对象,是一个合法的对象,然后操作它的成员函数
        Test(10);	// 产生临时对象   
        printf("main end
    ")
    
        return 0;
    }
    
    /*结果
    main begin
    Test()
    mi = 0	// 临时对象的打印
    ~Test()
    Test(int i)
    mi = 10	// 临时对象的打印
    ~Test()
    */
    

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

    #include <stdio.h>
    
    class Test
    {
        int mi;
    public:
        Test(int i)
        {
            printf("Test(int i) : %d
    ", i);
            mi = i;
        }
        Test(const Test& t)
        {
            printf("Test(const Test& t) : %d
    ", t.mi);
            mi = t.mi;
        }
        Test()
        {
            printf("Test()
    ");
            mi = 0;
        }
        int print()
        {
            printf("mi = %d
    ", mi);
        }
        ~Test()
        {
            printf("~Test()
    ");
        }
    };
    
    Test func()
    {
        return Test(20);	// 应该是返回一个临时对象
    }
    
    int main()
    {
     	Test t(10);
        Test t = Test(10);	// 1、生成一个临时对象;2、用临时对象初始化t 
        				   // ==> 调用拷贝构造函数
        				   // 但是结果并没有打印拷贝构造函数,说明编译器没有生成临时变量
        				   // 原因是现代编译器都会尽量减少临时变量的产生,
        				   // 编译器将这句话等价成了 Test t(10)
        				   // 临时变量的产生会带来性能上的问题
        t.print();	
        
        Test tt = func();
        tt.print();			// 会打印出20
        /*
        	理论上应该是要调用拷贝构造函数,但是没有
        	编译器将这句话等价成了 ==> Test tt = Test(20) ==> Test tt = 20;
        */
        
        return 0;
    }
    
    

    小结

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

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

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

    实际工程开发中需要认为地避开临时对象

  • 相关阅读:
    洛谷p1017 进制转换(2000noip提高组)
    Personal Training of RDC
    XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Eurasia
    XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Peterhof.
    Asia Hong Kong Regional Contest 2019
    XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Siberia
    XVIII Open Cup named after E.V. Pankratiev. Ukrainian Grand Prix.
    XVIII Open Cup named after E.V. Pankratiev. GP of SPb
    卜题仓库
    2014 ACM-ICPC Vietnam National First Round
  • 原文地址:https://www.cnblogs.com/chenke1731/p/9703397.html
Copyright © 2011-2022 走看看