
C++11
右值引用
这玩意是什么来着
反正是有左值和右值的区别来着
左值好像是一个有实际内存的书
右值是一个没有实际内存的数
(我可以这样理解吗?)
那么左值引用和右值引用的区别是什么呢?
为什么C++11中需要纳入右值引用?是为了解决什么问题呢?
或者是说能够实现什么优化呢?
为了减小开销,实际上move函数本身不是真正意义上实现“拷贝复制”,而是由对象b接受右值对象a的所有资源(如果底层是由指针来控制的话),并且将对象a 的控制权置空
右值引用理解和测试
报错原因:编码问题
右值机制验证
-
预设或者问题:在转移a资源的掌控之后,a会在什么时候被调用析构函数?以及被析构之前的指针指向究竟是什么?对象们的被析构顺序是?
-
验证代码
1 |
|
不对不对
我们是在验证右值
那么
这个已经被定义不算右值吧
但是可以被肯定的一点是
move()函数本身是需要用到右值移动函数的
1 | MyClass d; |
很明显看出被析构顺序的规律:谁先被创建谁就最后被析构
??这里应该是右值,为什么为什么不行
这里应该是调用了移动赋值函数,怎么不行呢?
加了一个还是不行
不知道为什么
它无论是左值的调用还是右值的调用都相当奇怪
是我们自己的加法有问题好吧
修改成int来试一下
我们要解决的问题是看清楚右值被调用的时机
为什么
为什么
MyClass c这一行右值没有被隐式调用右值引用
靠靠靠靠靠靠靠靠靠
尝试在stackflow中问答
1 |
|
答复:复制省略
https://en.cppreference.com/w/cpp/language/copy_elision
好像我看下来是编译器进行了复制省略
我还是不太懂
复制省略
定义
C++ 的省略复制(copy elision)是一种编译器优化技术,用于减少不必要的对象拷贝和临时对象的创建,从而提高程序的效率。在某些情况下,C++ 标准允许编译器跳过对象的复制和移动操作,即使这些操作在代码中显式地存在。这种优化在某些场景下是强制性的,而在另一些场景下则是可选的。
实现时机
参考网址
https://en.cppreference.com/w/cpp/language/copy_elision
https://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimization
chatgpt
自 C++17 以来,以下几种情况下编译器必须执行省略复制:
1.返回值优化(Return Value Optimization, RVO)
2.NRVO(Named Return Value Optimization)
1.RVO
旧情景:先在被调用函数的栈空间中创建该对象再复制或移动到调用者的空间。
优化成 ------->
新情景:当函数返回一个局部对象时,编译器可以直接在调用者的存储空间中构造这个对象
2.NRVO
当函数返回一个命名的局部对象时,编译器可以直接在调用者的存储空间中构造这个对象。
1
2
3
4 MyClass createObject() {
MyClass obj;
return obj; // 这里省略了构造临时对象和移动操作
}
实现机制
1. 返回值优化(RVO)
RVO 是最常见的一种省略复制优化技术。它在函数返回一个局部对象时,直接在调用者的内存空间中构造该对象,避免了临时对象的创建和后续的复制或移动操作。
实现原理:
- 当编译器检测到函数返回一个局部对象时,它会修改返回对象的存储位置,使其直接指向调用者的内存空间。
- 编译器在生成代码时,通过调整栈帧和对象的构造位置,确保对象直接在目标位置构造,而不在函数的栈空间中临时创建。
2. 命名返回值优化(NRVO)
NRVO 是 RVO 的扩展,适用于函数返回命名的局部对象的情况。
实现原理:
- 编译器跟踪命名对象的生命周期和返回路径,当确定返回的对象可以安全地在调用者的内存空间中构造时,它会进行相应的优化。
- 与 RVO 类似,编译器在代码生成阶段调整对象的构造位置和栈帧,使对象直接在目标位置构造。
3. 临时对象的优化
除了函数返回值优化,编译器还可以在其他场景中优化临时对象的创建,例如在表达式中创建的临时对象。
实现原理:
- 编译器在表达式分析阶段,检测临时对象的创建和使用情况,尽量避免不必要的对象复制。
- 通过内联展开和临时对象的合并,编译器可以减少临时对象的创建和析构次数。
4. 特定编译器的实现细节
不同的编译器可能有不同的实现细节,但总体思路是一致的。以下是一些具体编译器的实现方法:
GCC(GNU Compiler Collection)
GCC 通过在代码生成阶段对返回对象的存储位置进行优化来实现 RVO 和 NRVO。它使用内部数据结构和优化算法,确保对象在最合适的位置构造。
Clang/LLVM
Clang 使用 LLVM 中间表示(IR)进行优化。在生成 LLVM IR 时,Clang 会标记返回对象的存储位置,并在优化过程中合并临时对象,减少不必要的复制和移动操作。
MSVC(Microsoft Visual C++)
MSVC 通过在中间代码生成阶段优化对象的构造位置,利用其内部的优化算法和数据流分析技术,确保对象在最有效的位置构造,避免不必要的临时对象创建。
5. 标准库支持
C++ 标准库也支持省略复制。例如,在容器操作中(如 std::vector
的 emplace_back
),标准库函数会直接在目标位置构造对象,避免额外的临时对象创建。
结论
省略复制的实现依赖于编译器的智能优化技术,通过调整对象的构造位置和生命周期管理,避免不必要的复制和移动操作。这不仅提高了程序的性能,还减少了内存的使用和管理负担。现代编译器在这方面都有很好的支持,使得开发者可以在编写高效代码的同时,不需要过多关注底层的优化细节。
视频中的代码分析
每一个过程都要看清楚wow
每一个复制过程中都是在怎样的内存机制和数据行为下发生的!看清楚