QT(5.8版本)标准库源码主要在安装目录下的(VC找inlcude目录)

扩充内容的源码在

OOP 和 GP
oop(面向对象编程):Object-Oriented Programming,数据和操作放在一起(同一个类中)
GP(泛型编程):Generic Programming,数据和操作分开
使用GP:
Container和Algorithms团队可各自设计,其间以Iterators沟通即可
Algorithms通过Iterators确定操作范围,并通过Iterators取用Container元素

举例之:sort
源文件:stl_algo.h
有两个函数,分别是自定义从小到大版本,和允许接收仿函数自定义排序规则版本,两者都调用底层的 __sort函数

__sort是底层实现,重点在于对introsort_loop的调用,关于它的写法不同版本可能有些许不同,但重点在于它必须是可以随机访问的迭代器,即RandomAccessIterator,否则无法实现 *2(或/2)的操作,这也是为什么list不能使用::sort()的原因

c++ forward转发
在学习源码之前,需要先了解c++中的forward转发的用法
非常好的一篇:https://www.cnblogs.com/kaleidopink/p/13720773.html
右值引用原理:https://blog.youkuaiyun.com/m0_54850825/article/details/124761539
背景
背景:在C++11出现之前,C++传值默认是copy,但copy开销很大
举例:(a = b + c + d)中,c+d是一个临时变量, b+(c+d)又是另一个临时变量
右值:这些临时变量在C++11中被定义为右值(rvalue,read value),右值没有相应的变量名存储它们
左值:与右值相对的是左值(lvalue,localtor value),左值有变量名
场景:
class A {
...};
A a;
a.set("temp");//将"temp"复制给a的成员变量
可能的底层步骤:
临时变量"temp"在传参时先被复制一遍
被复制的内容放到a的成员变量中去
回收临时变量
可以改进的地方:临时变量既然是要回收的,那么可以直接使成员变量接管临时变量,就可以避免中间的复制过程
move和forward就是为此而产生的
左值引用和右值引用
左值引用
1. 原理
关于引用:&b=a实际上等价于int* const b=&a,而编译器会把&b编译为:&(*b)
它的实现是:将a的地址放到寄存器中,然后再将寄存器中的地址传给引用变量b
常量之所以可以左值引用,是因为它被放在静态存储区,是有地址的。而像是10这样的临时变量是放在寄存器中的,无法取址
2. 使用和注意事项
左值引用要求右值必须能够取地址,如果不能取地址,则必须为常引用。因为左值引用本质上是将地址赋给左值
int &b = a + 1;//错误,左值引用必须能够取地址
a+1不能被认为一个在内存中存在地址的变量,如果要这样用,需要加上const修饰。
同样的函数返回值不能使用左值引用,例如 int &a = func();这种情况要么修改为常引用或者不使用引用,但常引用会导致引用不可修改。
普通引用只能引用左值,不能引用右值,const引用既可引用左值,也可引用右值
当使用&b=a; 对b的操作相当于对(*b)的操作,即对a的操作
右值引用
1. 原理
int&& ref = 3;
临时变量(编译时未分配内存或使用寄存器存放的值)引用关联到右值时,右值被存储到特定位置
它的汇编指令和const &b = 3是一样的,只是后者不允许修改
用临时变量将3存起来,然后将地址送入寄存器;寄存器再将地址传给ref
变量和临时变量的值实际是按同一方式处理的,也就是说,临时变量根本上来说就是一个没有名字的变量而已,从汇编的角度来说,都是指针
C++引入右值引用,是为了延长临时变量的生命周期,避免昂贵的copy开销。相当于用指针直接接管这一块内存,而不是重新申请内存再复制
2. 使用和注意事项
右值引用可以处理临时变量的情况,即无法寻址的情况
类型 &&引用名 = 右值表达式;//定义格式
右值引用可以延长临时变量的生存周期,避免了无谓的内存复制操作。
C++11中右值引用:只能引用右值,一般情况不能直接引用左值
单纯的右值引用没有意义,它常与move和forward一起使用
引用叠加
int x = 1;
int&& r1 = x;//实际上这一步就会报错了
auto&& r2 = r1;
r2最终是一个左值引用
所有的右值引用叠加到右值引用上仍然是一个右值引用;
所有其他类型之间的叠加将会使得变成一个左值引用
move移动语义
参考:https://blog.youkuaiyun.com/u013015629/article/details/116525759
move是将对象的状态或者所有权从一个对象转移到另一个对象,只是转义,没有内存拷贝。
int d = 1;
int &&r = d;
上述操作是不被允许的,如果需要用右值引用接收左值,可以采用move函数(当不确定接收的是左值还是右值时可以这样使用)
int &&r = std::move(d);
而且move几乎没有代价,只是转移了资源的控制权。尽量可以用。
- 如果没有提供移动构造函数,只提供了拷贝构造函数,std::move()会失效但是不会发生错误,因为编译器找不到移动构造函数就去寻找拷贝构造函数,也这是拷贝构造函数的参数是const T&常量左值引用的原因
- c++11中的所有容器都实现了move语义,move只是转移了资源的控制权,本质上是将左值强制转化为右值使用,以用于移动拷贝或赋值,避免对含有资源的对象发生无谓的拷贝。move对于拥有如内存、文件句柄等资源的成员的对象有效,如果是一些基本类型,如int和char[10]数组等,如果使用move,仍会发生拷贝(因为没有对应的移动构造函数),所以说move对含有资源的对象说更有意义。
forward完美转发
move会将左值强制变成右值使用,而forward会保持原变量的属性
若对一个对象做move操作,就不要声明为 const. 因为对const对象的move请求会执行到copy操作上
void func(int&& i) {
cout << "rvalue: " << i << endl;
}
void func(int& i) {
cout << "lvalue: " << i << endl;
}
int main() {
int val = 2;
int &m1 = val;
//在不使用move或者forward时
func(m1);//lvalue
func(3);//rvalue
//使用move会将左值变成右值
func(std::move(m1));//rvalue
func(std::move(3

本文详细解析了C++中的右值引用和完美转发机制,包括其原理、应用场景及注意事项。并通过实例展示了如何利用move和forward来提高代码效率。
最低0.47元/天 解锁文章
1万+

被折叠的 条评论
为什么被折叠?



