C++第23课--神秘的临时变量

本文学习自 狄泰软件学院 唐佐林老师的 C++课程


实验1 :临时对象的引入
实验2:避免产生临时对象
实验3:临时对象的生成和声明周期1
实验4:临时对象的生成和声明周期2
实验5:C++编译器对减少临时对象所做的工作
实验6:实验5:C++编译器对减少临时对象所做的工作深入理解


要避免产生临时对象,在C语言中我们警惕是野指针,那么在C++里面我们最应该警惕是野指针和临时对象。


在这里插入图片描述

实验1 :临时对象的引入

#include <stdio.h>

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();

    return 0;
}


mhr@ubuntu:~/work/c++$ 
mhr@ubuntu:~/work/c++$ g++ 23-1.cpp 
mhr@ubuntu:~/work/c++$ ./a.out 
mi = 976883248
mhr@ubuntu:~/work/c++$ 

结果并不是我们预期的0,而是一个随机值。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

所以上面实验中 Test(0); ,从作用域和生命周期的角度分析,此处定义的临时对象没有任何作用,成员变量的值仍然是随机值。

    Test() {
        Test(0);//临时对象,作用域只在这一行代码,过了这一行代码 就消失了。
    }

等价于

    Test() {
       // Test(0);//临时对象,作用域只在这一行代码,过了这一行代码 就消失了。
    }

在C语言中我们警惕是野指针,那么在C++里面我们最应该警惕是野指针和临时对象


实验2:避免产生临时对象

#include <stdio.h>

class Test {
    int mi;
    
    /*
    init()就是一个普通的函数,并不是构造函数,所以调用init()不会生成临时对象。
    */
    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();

    return 0;
}

mhr@ubuntu:~/work/c++$ g++ 23-2.cpp
mhr@ubuntu:~/work/c++$ ./a.out 
mi = 0
mhr@ubuntu:~/work/c++$ 

实验3:临时对象的生成和声明周期1

#include <stdio.h>

class Test {
    int mi;
    
    /*
    init()就是一个普通的函数,并不是构造函数,所以调用init()不会生成临时对象。
    */
    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(1);//直接调用构造函数,将产生一个临时对象,马上构造马上析构
	
	printf("main end\n");
    return 0;
}

mhr@ubuntu:~/work/c++$ 
mhr@ubuntu:~/work/c++$ g++ 23-1.cpp
mhr@ubuntu:~/work/c++$ ./a.out 
main begin
Test()
~Test()
Test(int i)
~Test()
main end
mhr@ubuntu:~/work/c++$ 

实验4:临时对象的生成和声明周期2

#include <stdio.h>

class Test {
    int mi;
    
    /*
    init()就是一个普通的函数,并不是构造函数,所以调用init()不会生成临时对象。
    */
    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().print();//直接调用构造函数,将产生一个临时对象,在通过临时对象调用成员函数,最后析构
	Test(1).print();//直接调用构造函数,将产生一个临时对象,在通过临时对象调用成员函数,最后析构
	
	printf("main end\n");
    return 0;
}


mhr@ubuntu:~/work/c++$ 
mhr@ubuntu:~/work/c++$ g++ 23-1.cpp
mhr@ubuntu:~/work/c++$ ./a.out 
main begin
Test()
mi = 0
~Test()
Test(int i)
mi = 1
~Test()
main end
mhr@ubuntu:~/work/c++$ 

在这里插入图片描述

实验5: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 = Test(10) ==>  Test t(10)  ==> Test t = 10
	Test t = Test(10);//1. 生成临时对象  2.用临时对象初始化(调用拷贝构造函数 )
	*/
	Test t = Test(10);
    t.print();
    return 0;
}


mhr@ubuntu:~/work/c++$ g++ 23-3.cpp
mhr@ubuntu:~/work/c++$ ./a.out 
Test(int i) : 10
mi = 10
~Test()
mhr@ubuntu:~/work/c++$ 

问题1:结果显示并没有调用拷贝构造函数啊,这是为什么呢?
答案1:这是因为现代 C++编译器在不影响最终结果的前提下,会尽力的减少临时对象的产生,编译器直接将

Test t = Test(10);

替换为

Test t = 10

从而杜绝了临时对象的产生。

问题2:为什么C++编译器要杜绝临时对象的产生呢?
答案2:由上面的例子可以看出 如果编译器按照原生程序的写法 Test t = Test(10); 来执行程序的话,需要调用两次构造函数再加上一次拷贝构造函数,效率会远远低于 Test t = 10;的写法,只调用一次构造函数。

实验6:实验5: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 = Test(10); // ==> Test t = 10;
    Test tt = func();  // ==> Test tt = Test(20); ==> Test tt = 20;
    
    t.print();
    tt.print();
    
    return 0;
}


mhr@ubuntu:~/work/c++$ 
mhr@ubuntu:~/work/c++$ g++ 23-3.cpp
mhr@ubuntu:~/work/c++$ ./a.out 
Test(int i) : 10
Test(int i) : 20
mi = 10
mi = 20
~Test()
~Test()
mhr@ubuntu:~/work/c++$ 

在这里插入图片描述

发布了207 篇原创文章 · 获赞 100 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/LinuxArmbiggod/article/details/104103434