右值以及移动函数

右值与移动语义详解

右值以及移动函数

如果称 &i = a; i是左值运算; 那&&i = a为右值运算;

**当然为右值运算右边的值应该为一个常数; **

正是新定义的右值运算, 也就有了移动函数;


#include <iostream>
#include <cstdlib>
#include <string>
#include <utility>
#include <vector>

//移动拷贝;
//移后源对象必须可析构;
class T1
{
public:
	T1() = default;
	~T1() = default;
	T1(const T1 &) = default;

	//赋值运算符既是移动运算符, 也是拷贝赋值运算符;
	T1 & operator = (T1 t1) { std::swap(*this, t1); return *this; }
	//noexcept : 保证程序的移动函数是绝对正确 没有异常的;
	T1(T1 &&t1) noexcept : x(t1.x), str(t1.str) {}

	//引用限定符;
	T1 & operator = (const T1 &) &;			//只能向可修改的左值赋值
	//T1 Fun() & const; 只能将 & 放在const之后;
	T1 Fun() const &; 						//可用于任何类型的T1;
	T1 Fun1() && ;							//只能用于可改变的右值;

private:
	int x;
	std::string str;
};
//T1::T1(T1 &&t1) noexcept
//{
//	x = t1.x;
//	str = t1.str;
//}



int main()
{
	//右值引用;
	//右边的值是非变量, 而且这样右侧的值即将被销毁; 右侧的只能用于销毁和赋值操作;
	int i = 0;
	int &x1 = i;
	int &&x2 = 1;
	int &&x3 = i * i;
	int &&x4 = std::move(x3);
	x3 = 32;						//当x3改变时, x4也会改变
	std::cout << x3 << " " << x4;

	system("pause");
	return 0;
}


当然, 自己看右值的时候已经很蒙了, 还是等很久再来重温它应该会理解更深刻;

### C++ 中引用和移动语义的使用与原理 #### 什么是引用? 引用是一种特殊的引用类型,它绑定到所谓的“”。通常是指表达式的临时结果或即将销毁的对象。C++11引入了引用的概念,其主要目的是为了支持移动语义[^4]。 引用通过`&&`表示法定义。例如: ```cpp int &&rvalue_ref = 5; ``` 这里,`rvalue_ref`是一个引用,绑定了字面`5`,这是一个临时对象。 #### 引用的特点 - 引用可以绑定到临时对象(即),而普通的左引用无法做到这一点。 - 绑定到引用的对象具有左特性,因此可以通过引用来修改该对象的内容[^3]。 #### 移动语义的作用 传统的拷贝构造函数和赋运算符在处理大型对象时可能会非常低效,因为它们涉及深拷贝操作。移动语义的核心思想是从源对象中“窃取”资源,而不是复制这些资源。这显著提升了性能,尤其是在处理动态分配内存或其他昂贵资源的情况下。 ##### 实现移动语义的关键组件 1. **移动构造函数** 当创建一个新的对象时,如果参数是,则调用移动构造函数。例如: ```cpp class MyString { char* data; public: // 构造函数 MyString(const char* str) : data(new char[strlen(str)+1]) { strcpy(data, str); } // 拷贝构造函数 MyString(const MyString& other) : data(new char[strlen(other.data)+1]) { strcpy(data, other.data); } // 移动构造函数 MyString(MyString&& other) noexcept : data(nullptr) { data = other.data; // 窃取资源 other.data = nullptr; // 防止析构时释放两次 } ~MyString() { delete[] data; } }; ``` 2. **移动运算符** 类似于移动构造函数,当一个已存在的对象被赋予另一个时,调用移动运算符。例如: ```cpp MyString& operator=(MyString&& other) noexcept { if (this != &other) { delete[] data; // 释放原有资源 data = other.data; // 窃取资源 other.data = nullptr; // 设置为空指针 } return *this; } ``` #### 如何触发移动语义? 移动语义通常是隐式触发的,特别是在以下情况下: - 返回局部变量作为函数的结果。 - 显式调用`std::move()`将左转换为。 例如: ```cpp #include <iostream> using namespace std; class MyClass { public: int* ptr; MyClass(int size) : ptr(new int[size]{}) {} MyClass(MyClass&& other) noexcept : ptr(other.ptr) { other.ptr = nullptr; cout << "Move constructor called." << endl; } ~MyClass() { delete[] ptr; } }; MyClass createObject() { MyClass obj(100); // 创建了一个大数组 return obj; // 自动触发移动构造函数 } int main() { MyClass myObj = createObject(); // 调用了移动构造函数 } ``` 在这个例子中,由于返回的是局部变量`obj`,编译器会选择移动构造函数而非拷贝构造函数来初始化`myObj`。 #### `std::move` 的作用 `std::move` 是一种工具函数,用于显式地将左转化为。它的本质是对类型的强制转换,从而让编译器认为某个对象是可以被“移动”的。例如: ```cpp MyClass a(10); MyClass b = std::move(a); // 手动触发移动构造函数 ``` 需要注意的是,`std::move` 并不会实际执行任何移动操作;它只是改变对象的身份标记,使其成为。 --- ### 总结 引用和移动语义共同构成了现代C++高效管理资源的重要机制。通过减少不必要的深拷贝操作,程序可以在不牺牲安全性的前提下获得更高的运行效率。这种技术广泛应用于标准库容器(如`vector`)、字符串类以及其他复杂的数据结构中[^5]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值