ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

【无标题】C++3:拷贝构造以及编译器优化

【无标题】C++3:拷贝构造以及编译器优化

this指针

我们在创建变量时,如果名字与类的普通成员方法名字相撞,那我们应该如何区分到底是把哪个值赋给谁呢?这时候就引出this指针,可以区别

classTest{public:intnum;// 成员变量voidsetNum(intnum){// this->num:类自身的成员变量// num:传入的形参局部变量this->num=num;}

由此我们引出this指针定义
你创建一个类的实例(对象),电脑会在内存里给它单独划分一块地盘;
对象调用自己的成员函数时,编译器会自动把这个对象的内存地址打包成this,偷偷传给成员函数;
在成员函数内部,this就代表 “正在干活的这个对象自己”。
总之:谁调用这个成员函数,this就指向谁
△ this指针专门指向调用该方法的对象

拷贝构造

咱们在重新构造一个和之前某一个一摸一样的对象时,就叫拷贝构造。
但是拷贝构造分为浅拷贝与深拷贝。
默认拷贝构造视为浅拷贝,浅拷贝就例如照着蛋糕 A 的样子,复刻一块配料、造型完全一致的新蛋糕 B,全程不用重新走一遍基础配料初始化。

classPerson{public:intage;// 手动实现默认风格的拷贝构造Person(constPerson&p){age=p.age;}};intmain(){Personp1(18);// 普通构造,造出第一个对象Personp2(p1);// 调用拷贝构造,照着p1复制出全新p2return0;}`` 为什么需要深拷贝呢? 浅拷贝只是单纯把指针变量里存的地址原样复制一份。 两个对象的指针指向同一块堆内存: 对象 A 释放内存delete;对象 B 的指针变成野指针;等到 B 析构再次执行delete,程序直接崩溃(重复释放同一块内存)。 深拷贝如下 ```cpppublic:intage;char*name;// 堆区动态开辟的字符串,必须深拷贝Person(constPerson&p){age=p.age;//自己新开一块堆内存,而不是直接复制指针地址name=newchar[strlen(p.name)+1];strcpy(name,p.name);}// 析构函数释放堆内存~Person(){delete[]name;}intmain(){Personp1(20,"小明"); Person p2 (p1);return0;}

那什么时候要深拷贝呢?
1… 类内包含手动 new/malloc 在堆上开辟的内存
2. 独占资源

赋值

per1=per2看似是赋值,其实调用了per1的operator=函数

//per1=per2Person&operator=(constPerson&p){if(this==&p){return*this;//防止自己给自己赋值}delete[]this->name;// 拷贝普通成员this->age=p.age;//this->name=newchar[strlen(p.name)+1];strcpy(this->name,p.name);// 返回自身引用,支持连续赋值 p1=p2=p3return*this;

什么是explicit?
在未加关键字前会出现隐式转换
加完之后写Person p = 18; test(20);
会报错,但是可以

// 方式1Personp(18);// 方式2Person p=Person(18);// 方式3test(Person(20));

C++编译器对临时对象的优化

1.使用临时对象拷贝构造同类型新对象,临时对象被优化
使用构造临时对象的方式,直接构造新对象即可
例如person per4(Person("z张飞",23,‘M’))就不会构造临时对象,直接构造出来相当于per4(“张飞”,23,‘M’)
2.但是如果你进行赋值的话,那么临时对象不会被优化,因为一旦优化就无法对新对象进行赋值

PersonGetperson(person per){constchar*name=per.getName();intage=per.getAge();charsex=per.getSex();PersontmpPer(name,age,sex);returntmpPer;}intmain(){Personper1("x“,“22”,“m”);Person per2;per2=Getperson(per1);per2.show;}

以上这段代码我们可以理解为,从main函数开始分析,先进行per1的三个参数构造,再进行per2的默认构造,然后实参到形参是一个拷贝构造,编译器直接优化(不再拷贝构造tmpPer),生成一个main函数栈上的临时对象然后对per2进行赋值操作

PersonGetperson(person per){constchar*name=per.getName();intage=per.getAge();charsex=per.getSex();PersontmpPer(name,age,sex);returntmpPer;}intmain(){Personper1("x“,“22”,“m”);Person per2=Getperson(per1);per2.show;}

我们从Person per2=Getperson(per1);开始分析:本来的顺序Getperson 值接收参数,把 per1 拷贝一份得到栈上形参 per;在 Getperson 函数自身栈空间里,正常构造局部对象 tmpPer(调用普通构造函数);把 tmpPer 拷贝构造一份放到 main 栈的返回值临时对象;再用这个临时对象,拷贝构造 main 里的 per2;函数退出销毁 tmpPer、形参 per,最后析构临时、per1、per2。但是编译器优化时,直接就把tmpPer当成per2进行常规构造

心得总结

本节课主要内容为this指针,拷贝构造,赋值函数,C++编译器优化,我认为this指针指向被调用方法的对象是一个很重要的点,在此之前我一直以为this指针是每个参数都拥有的,其次拷贝构造中我认为为什么会出现深拷贝这种问题是很重要的,只有知道为什么需要深拷贝我们才能了解深拷贝的底层原理,C++编译器优化中比较难的我认为是何时临时对象会进行赋值而何时不能够省略临时对象,这需要再琢磨琢磨,以上包含我这节课所认为重点核心难点以及还未攻克的难题

返回列表