对于C++11提出了左值、右值的概念。
左值 (location value)
-
定义:左值是指可以出现在赋值运算符左侧的表达式。它通常代表一个持久的对象(即有持久的内存地址),可以在之后的代码中引用。
-
特点:
- 有持久的内存地址。
- 可以被修改。
- 可以取地址(使用
&
运算符)。
-
示例:
-
int x = 10; // x 是一个左值 x = 20; // 可以将新值赋给 x int* p = &x; // 可以取 x 的地址
右值 (read value)
-
定义:右值是指临时对象或不具备持久存储的对象,通常用来表示计算结果。右值通常出现在赋值运算符右侧。
-
特点:
- 没有持久的内存地址。
- 通常是匿名的。
- 不能取地址,或者取地址的意义不大。
-
示例:
-
int y = 5 + 10; // "5 + 10" 是一个右值 int* p = &y; // y 是一个左值,而 "5 + 10" 不是
右值引用
C++11 引入了右值引用(rvalue reference),这使得程序能够识别右值并进行优化,比如通过移动语义(move semantics)来提高性能。这可以通过使用 &&
来定义右值引用。
- 示例:
-
void process(int&& val) { // val 是一个右值引用 // ... } process(42); // 42 是一个右值
总结
- 左值:有持久性,可以取地址,能出现在赋值运算符的左侧。
- 右值:没有持久性,通常是临时对象,出现在赋值运算符的右侧。
使用场景
了解左值和右值的概念有助于:
- 理解 C++ 的资源管理与优化。
- 编写高效的代码,特别是在处理移动语义和完美转发时。
案例实现
#include <iostream>
#include <string.h>
#include <algorithm>
#include <type_traits>
using namespace std;
class CharBuffer {
public:
CharBuffer() :m_buff(nullptr), m_Size(0) {
cout << "默认构造函数" << endl;
}
CharBuffer(unsigned int nSize) :m_buff(new char[nSize]), m_Size(nSize) {
cout << "普通构造函数" << endl;
}
CharBuffer(CharBuffer& other) :m_buff(new char[other.m_Size]), m_Size(other.m_Size) {
memcpy(m_buff, other.m_buff, m_Size);
cout << "拷贝构造函数" << endl;
}
CharBuffer(CharBuffer&& other) :m_buff(other.m_buff), m_Size(other.m_Size) {
other.m_buff = nullptr;
other.m_Size = 0;
cout << "移动构造函数" << endl;
}
CharBuffer& operator=(const CharBuffer& other) {
if (m_Size == 0 || m_Size != other.m_Size) {
if (m_Size != other.m_Size) {
delete[] m_buff;
}
m_buff = new char[other.m_Size];
m_Size = other.m_Size;
}
memcpy(m_buff, other.m_buff, m_Size);
cout << "拷贝赋值运算符" << endl;
return *this;
}
CharBuffer& operator=(CharBuffer&& other) {
if (m_Size) {
delete[] m_buff;
}
m_buff = other.m_buff;
m_Size = other.m_Size;
other.m_buff = nullptr;
other.m_Size = 0;
cout << "移动赋值运算符" << endl;
return *this;
}
static CharBuffer& assign(CharBuffer& to, CharBuffer& from) {
to = from;
return to;
}
static CharBuffer& assign(CharBuffer& to, CharBuffer&& from) {
to = from;
return to;
}
~CharBuffer() {
delete[] m_buff;
cout << "析构函数" << endl;
}
private:
char* m_buff;
unsigned int m_Size;
};
template <class T>
CharBuffer makeObj(T&& buf) {
cout << "是否左值 :" << is_lvalue_reference<T&&>::value << endl;
cout << "是否右值 :" << is_rvalue_reference<T&&>::value << endl;
// 左值引用:为对象起一个别名
// 右值引用:为即将废弃的对象续命
return CharBuffer((T&&)buf);
}
CharBuffer getObj(int n) {
CharBuffer buf(n);
return buf;
}
int main()
{
CharBuffer buf1(CharBuffer(100));
cout << "-----------------------------------" << endl;
// 移动构造
CharBuffer buf2 = getObj(100);
// 移动赋值
buf2 = getObj(200);
cout << "-----------------------------------" << endl;
CharBuffer buf3;
CharBuffer buf4(100);
CharBuffer::assign(buf3, std::move(buf4));
cout << "-----------------------------------" << endl;
CharBuffer buf5(100);
// 拷贝构造
makeObj(buf5);
cout << "-----------------------------------" << endl;
// 移动构造
makeObj(std::move(buf5));
return 0;
}
执行结果如下: