• 二十一、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++编译器会尽力避开临时对象

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

  • 相关阅读:
    Servlet编程寄语
    filter常用功能
    Javascript的自动、定时执行和取消
    CentOS 5安装GIT的基本命令
    EF调用执行Oracle中序列
    WCF使用IIS发布服务的配置
    linux 自学系列:debian更新软件列表、更改源
    shell编程笔记五:select
    linux 自学系列: 改IP地址,主机名及DNS
    shell编程笔记四:case in
  • 原文地址:https://www.cnblogs.com/chenke1731/p/9703397.html
Copyright © 2020-2023  润新知