二十一、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\n", 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)\n");
        init(i);
    }

    Test(){
        printf("Test()\n");
        init(0);	// 调用的普通私有函数,不会产生临时对象
    };
    
    void print() {
        printf("mi = %d\n", mi);
    }
    
    ~Test()
    {
        printf("~Test()\n");
    }
};



int main()
{
    printf("main begin\n");
    
    Test();		// 直接调用构造函数,会产生一个临时对象
    Test(10);	// 产生临时对象
    
    printf("main end\n")

    return 0;
}

/*结果
main begin
Test()
~Test()
Test(int i)
~Test()
*/

int main()
{
    printf("main begin\n"); 
    Test().print();		// Test()结果是一个临时对象,是一个合法的对象,然后操作它的成员函数
    Test(10);	// 产生临时对象   
    printf("main end\n")

    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\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(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++编译器会尽力避开临时对象

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

posted @ 2018-09-25 20:44  小胖鼠  阅读(256)  评论(0编辑  收藏  举报