@@ -13,29 +13,29 @@ Index
1313<!-- TOC -->
1414
1515- [ 小结] ( #小结 )
16- - [ 左值引用类型 与 右值引用类型] ( #左值引用类型-与-右值引用类型 )
17- - [ 当发生自动类型推断时,` T&& ` 也能绑定左值] ( #当发生自动类型推断时t-也能绑定左值 )
18- - [ 如何快速判断左值与右值] ( #如何快速判断左值与右值 )
19- - [ 引用折叠规则] ( #引用折叠规则 )
20- - [ ` move() ` 与 ` forward() ` ] ( #move-与-forward )
16+ - [ 左值引用类型 与 右值引用类型] ( #左值引用类型-与-右值引用类型 )
17+ - [ 当发生自动类型推断时,` T&& ` 也能绑定左值] ( #当发生自动类型推断时t-也能绑定左值 )
18+ - [ 如何快速判断左值与右值] ( #如何快速判断左值与右值 )
19+ - [ 引用折叠规则] ( #引用折叠规则 )
20+ - [ ` move() ` 与 ` forward() ` ] ( #move-与-forward )
2121- [ 左值与右值的本质] ( #左值与右值的本质 )
22- - [ 左值、消亡值、纯右值] ( #左值消亡值纯右值 )
22+ - [ 左值、消亡值、纯右值] ( #左值消亡值纯右值 )
2323- [ 右值引用的特点] ( #右值引用的特点 )
24- - [ 右值引用延长了临时对象的生命周期] ( #右值引用延长了临时对象的生命周期 )
25- - [ 利用右值引用避免临时对象的拷贝和析构] ( #利用右值引用避免临时对象的拷贝和析构 )
26- - [ 右值引用类型绑定的一定是右值,但 ` T&& ` 可能不是右值引用类型] ( #右值引用类型绑定的一定是右值但-t-可能不是右值引用类型 )
27- - [ 当发生自动类型推断时,` T&& ` 是未定的引用类型] ( #当发生自动类型推断时t-是未定的引用类型 )
24+ - [ 右值引用延长了临时对象的生命周期] ( #右值引用延长了临时对象的生命周期 )
25+ - [ 利用右值引用避免临时对象的拷贝和析构] ( #利用右值引用避免临时对象的拷贝和析构 )
26+ - [ 右值引用类型绑定的一定是右值,但 ` T&& ` 可能不是右值引用类型] ( #右值引用类型绑定的一定是右值但-t-可能不是右值引用类型 )
27+ - [ 当发生自动类型推断时,` T&& ` 是未定的引用类型] ( #当发生自动类型推断时t-是未定的引用类型 )
2828- [ 常量(左值)引用] ( #常量左值引用 )
2929- [ 返回值优化 RVO] ( #返回值优化-rvo )
3030- [ 移动语义] ( #移动语义 )
31- - [ 深拷贝带来的问题] ( #深拷贝带来的问题 )
32- - [ 移动构造函数] ( #移动构造函数 )
33- - [ 移动语义 与 ` move() ` ] ( #移动语义-与-move )
34- - [ ` move() ` 的本质] ( #move-的本质 )
35- - [ ` move() ` 的原型 TODO] ( #move-的原型-todo )
31+ - [ 深拷贝带来的问题] ( #深拷贝带来的问题 )
32+ - [ 移动构造函数] ( #移动构造函数 )
33+ - [ 移动语义 与 ` move() ` ] ( #移动语义-与-move )
34+ - [ ` move() ` 的本质] ( #move-的本质 )
35+ - [ ` move() ` 的原型 TODO] ( #move-的原型-todo )
3636- [ 完美转发] ( #完美转发 )
37- - [ ` forward<T>() ` 实现完美转发] ( #forwardt-实现完美转发 )
38- - [ ` forward<T>() ` 的原型 TODO] ( #forwardt的原型-todo )
37+ - [ ` forward<T>() ` 实现完美转发] ( #forwardt-实现完美转发 )
38+ - [ ` forward<T>() ` 的原型 TODO] ( #forwardt的原型-todo )
3939- [ Reference] ( #reference )
4040
4141<!-- /TOC -->
@@ -320,49 +320,49 @@ int&& v2 = v1; // err: v2 是右值引用类型,但 v1 是左值
320320 construct: 1 // 构造局部变量 a,在编译的优化下,相当于直接将 a “改名” aa
321321 destruct: 1 // 程序结束,析构变量 aa
322322 ```
323- - 返回值优化并不是 C++ 的标志 ,是各编译器优化的结果,但是这项优化并不复杂,所以基本流行的编译器都提供
323+ - 返回值优化并不是 C++ 的标准 ,是各编译器优化的结果,但是这项优化并不复杂,所以基本流行的编译器都提供
324324
325325
326326## 移动语义
327327
328328### 深拷贝带来的问题
329329- 带有**堆内存**的类,必须提供一个深拷贝构造函数,以避免“指针悬挂”问题
330- > 所谓指针悬挂,指的是两个对象内部的成员指针变量指向了同一块地址,析构时这块内存会因被删除两次而发生错误
331- ```Cpp
332- class A {
333- public:
334- A(): m_ptr(new int(0)) { // new 堆内存
335- cout << "construct" << endl;
336- }
337-
338- A(const A& a):m_ptr(new int(*a.m_ptr)) { // 深拷贝构造函数
339- cout << "copy construct" << endl;
340- }
341-
342- ~A(){
343- // cout << "destruct" << endl;
344- delete m_ptr; // 析构函数,释放堆内存的资源
345- }
346- private:
347- int* m_ptr; // 成员指针变量
348- };
349-
350- A getA() {
351- return A();
352- }
353-
354- int main() {
355- A a = getA();
356- return 0;
357- }
358- ```
359- - 输出(关闭 RVO)
360- ``` Cpp
361- construct
362- copy construct
363- copy construct
364- ```
365- > 如果不关闭 RVO,只会输出 ` construct `
330+ > 所谓指针悬挂,指的是两个对象内部的成员指针变量指向了同一块地址,析构时这块内存会因被删除两次而发生错误
331+ ```Cpp
332+ class A {
333+ public:
334+ A(): m_ptr(new int(0)) { // new 堆内存
335+ cout << "construct" << endl;
336+ }
337+
338+ A(const A& a):m_ptr(new int(*a.m_ptr)) { // 深拷贝构造函数
339+ cout << "copy construct" << endl;
340+ }
341+
342+ ~A(){
343+ // cout << "destruct" << endl;
344+ delete m_ptr; // 析构函数,释放堆内存的资源
345+ }
346+ private:
347+ int* m_ptr; // 成员指针变量
348+ };
349+
350+ A getA() {
351+ return A();
352+ }
353+
354+ int main() {
355+ A a = getA();
356+ return 0;
357+ }
358+ ```
359+ - 输出(关闭 RVO)
360+ ```Cpp
361+ construct
362+ copy construct
363+ copy construct
364+ ```
365+ > 如果不关闭 RVO,只会输出 `construct`
366366- 提供深拷贝能够保证程序的正确性,但会带来额外的性能损耗——临时对象也会申请一块内存,然后又马上被销毁了;如果堆内存很大的话,这个性能损耗是不可忽略的
367367- 对于临时对象而言,深拷贝不是必须的
368368- 利用右值引用可以避免无谓的深拷贝——移动拷贝构造函数
0 commit comments