undefined

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
一. 关于栈上的内存分配
1. 栈上的内存分配极为简单,移动一下栈指针即可
2. 栈上的释放内存也极为简单,函数执行结束时移动一下栈指针即可
3. 由于后进先出的执行过程,不可能出现内存碎片
对于有构造和析构函数的非简单类型,c++编译器会在生成代码的合适位置,插入对构造和析构函数的调用。编译器会自动调用析构函数,包括在函数执行发生异常的情况。

二. RAII
c++支持将对象存储在栈上面,但某些情况对象不能存储在栈上。比如:
1. 对象很大
2. 对象的大小在编译时不能确定
3. 对象是函数的返回值,但由于特殊的原因,不应使用对象的值返回

不要返回本地变量的引用。在c++11之前,返回一个本地对象意味着这个对象会被拷贝,除非编译器发现可以做返回值优化(named return value optimization,或NRVO),能把对象直接构造到调用者的栈上。从c++11开始,返回值优化仍可以发生,但在没有返回值优化的情况下,编译器将试图把本地对象移动出去,而不是拷贝出去。这一行为不需要手工用 std::move() 干预,使用 std::move() 反而会影响返回值优化。

引用坍缩/引用折叠
在模版的使用中
template<typename T>
void f(T&& param)
f(10); // 10 是右值
int x = 10;
f(x); // x 是左值

这种未定的引用类型称为 universal references,这种类型必须被初始化,而他是左值还是右值则取决于他的初始化,如果被左值初始化,那它就是左值,反之亦然。
由于存在 T&& 这种未定的引用类型,当它作为参数时,又可能被一个左值引用或右值引用的参数初始化,这是经过类型推导的 T&& 类型,相比右值引用(&&)会发生类型的变化,这种变化就称为引用折叠
1. 所有右值引用折叠到右值引用上仍然是一个右值引用 (A&&&& 变成 A&&)
2. 所有的其他引用类型之间的折叠都将变成左值引用 (A&& 变成 A&; A&&& 变成 A&)
简单一点,如下:
1. 对于 template<typename T> foo(T&&) 这样的代码,如果传递过去的参数时左值,T的推导结果是左值引用;如果传递过去的参数是右值,T的推导结果是参数的类型本身
2. 如果 T 是左值引用,那 T&& 的结果仍然是左值引用---type&&& 坍缩为 type&
3. 如果 T 是一个实际类型,那 T&& 的结果自然就是一个右值引用

完美转发
保持参数的值类型:左值仍然是左值,右值仍然是右值。不改变原值的属性
实现原理:实现了两个模版函数,一个接收左值,另一个接收右值