一、左值的特征和用途
- 可寻址性:左值是可以通过取地址得到的表达式,具有持久性。
- 持久性:左值的生命周期通常与包含它的作用域相同。
- 修改性:左值可以用于修改变量的值,是可被赋值的对象。
int x = 42; // x 是左值
int y = x; // x 可以被赋值给 y
二、右值的特征和用途
- 临时性:右值通常是临时生成的,其生命周期可能只在表达式结束时。
- 表达式结果:右值可以是表达式的结果,也可以是字面量或临时对象。
- 初始化:右值常用于初始化操作,将值传递给其他对象。
int getResult() { return 42; }
int y = getResult(); // getResult() 是右值
三、移动语义和右值引用
移动语义的背景
传统的复制操作可能涉及大量资源的复制,引入了移动语义来解决右值的所有权和性能问题。
右值引用的概念
- 引入
&&
表示右值引用,允许我们对右值进行引用操作。 - 示例:
T&&
表示对类型T
的右值引用。
template <typename T>
void processRValue(T&& rvalueRef) {
// 对右值进行操作
}
移动语义的实现
- 移动构造函数和移动赋值运算符用于实现移动语义。
- 通过
std::move
转换左值为右值引用,避免资源的不必要复制。
class Example {
public:
// 移动构造函数
Example(Example&& other) noexcept {
// 执行资源的转移操作
}
// 移动赋值运算符
Example& operator=(Example&& other) noexcept {
// 执行资源的转移操作
return *this;
}
};
Example createExample() {
Example temp;
// 生成临时对象
return temp;
}
Example obj = createExample();
完美转发
完美转发的需求
函数模板和泛型编程中,需要处理各种类型的左值和右值,引入完美转发来解决参数传递的问题。
std::forward
的作用
std::forward
用于在函数中进行完美转发,保持参数原有的左值或右值特性。- 示例:使用
std::forward
进行完美转发。
template <typename T>
void forwardFunction(T&& arg) {
processRValue(std::forward<T>(arg));
}
右值优化和 RVO
右值优化的概念
编译器通过右值优化(RVO)来减少临时对象的创建,提高效率。
返回值优化(RVO)
- 返回值优化是一种编译器在函数返回时避免不必要的临时对象创建的优化手段。
- 示例:演示 RVO 的使用场景。
Example createExample() {
Example temp;
// 生成临时对象
return temp; // 可能会被 RVO 优化
}
四、研究左值右值的测试代码
#include <iostream>
#include <string>
#include <vector>
class Test {
public:
Test() {
std::cout << "Test" << std::endl;
}
//析构函数
~Test() {
if (data_) {
std::cout << "[" << data_ << "] ~Delete" << std::endl;
delete data_;
data_ = nullptr;
}
}
//左值函数
Test( Test &other) noexcept {
std::cout << "[" << other.data_ << "] Left copy" << std::endl;
data_ = new char[4];
memcpy(data_, other.data_, 4);
}
//右值函数
Test(Test &&other) noexcept {
std::cout << "[" << other.data_ << "] Right copy" << std::endl;
data_ = other.data_;
other.data_ = nullptr;
}
public:
char *data_{nullptr};
};
int main() {
std::vector<Test> vec;
for (uint32_t idx = 0; idx < 10; idx++) {
std::cout << "------------------- start --------------------" << std::endl;
Test test;
std::string data = std::to_string(idx);
test.data_ = new char[12];
std::strcpy(test.data_, data.c_str());
vec.emplace_back(test);
std::cout << "------------------- end --------------------" << std::endl;
}
return 0;
}
运行结果:
C:\Users\CLionProjects\untitled\cmake-build-debug\untitled.exe
------------------- start --------------------
Test
[0] Left copy
------------------- end --------------------
[0] ~Delete
------------------- start --------------------
Test
[1] Left copy
[0] Right copy
------------------- end --------------------
[1] ~Delete
------------------- start --------------------
Test
[2] Left copy
[0] Right copy
[1] Right copy
------------------- end --------------------
[2] ~Delete
------------------- start --------------------
Test
[3] Left copy
[0] Right copy
[1] Right copy
[2] Right copy
------------------- end --------------------
[3] ~Delete
------------------- start --------------------
Test
[4] Left copy
[0] Right copy
[1] Right copy
[2] Right copy
[3] Right copy
------------------- end --------------------
[4] ~Delete
------------------- start --------------------
Test
[5] Left copy
------------------- end --------------------
[5] ~Delete
------------------- start --------------------
Test
[6] Left copy
[0] Right copy
[1] Right copy
[2] Right copy
[3] Right copy
[4] Right copy
[5] Right copy
------------------- end --------------------
[6] ~Delete
------------------- start --------------------
Test
[7] Left copy
------------------- end --------------------
[7] ~Delete
------------------- start --------------------
Test
[8] Left copy
------------------- end --------------------
[8] ~Delete
------------------- start --------------------
Test
[9] Left copy
[0] Right copy
[1] Right copy
[2] Right copy
[3] Right copy
[4] Right copy
[5] Right copy
[6] Right copy
[7] Right copy
[8] Right copy
------------------- end --------------------
[9] ~Delete
[0] ~Delete
[1] ~Delete
[2] ~Delete
[3] ~Delete
[4] ~Delete
[5] ~Delete
[6] ~Delete
[7] ~Delete
[8] ~Delete
[9] ~Delete
进程已结束,退出代码0