C++ 教程: 用std::move来移动所有权
2025年5月19日 05:29
📘 C++ 移动语义与 std::move() 教程
C++的std::move用于转移变量/对像的所有权/Ownership。
🔹 什么是移动语义?
在 C++ 中,移动语义通过转移资源所有权/Ownership(如内存或文件句柄)来优化性能,而不是复制它们。
移动语义是在 C++11 中引入的,它允许:
- 更快速地传递大型或昂贵的对象
- 更高效地使用临时值
🔹 什么是 std::move()?
std::move(x)
并不会真的移动任何东西 —— 它只是将 x
转换为一个 右值引用(即 T&&
),告诉编译器:
“你可以把这个对象当作临时对象来处理并移动它。”
要真正实现移动,你的类型必须实现 移动构造函数 或 移动赋值运算符。
✅ 什么时候该用 std::move()?
在以下情况下使用它:
- 你想 转移资源的所有权。
- 你正在处理 复制开销大的对象(如
std::string
、std::vector
、unique_ptr
)。 - 你写的函数按值接收参数,并希望将其移动进成员变量。
🔍 std::string 示例
#include <iostream> #include <string> #include <utility> int main() { std::string a = "hello"; std::string b = std::move(a); std::cout << "b: " << b << std::endl; std::cout << "a: " << a << std::endl; }
🔍 移动 std::vector
std::vector<int> original = {1, 2, 3}; std::vector<int> moved_to = std::move(original); // original 现在为空(但仍然有效)
⚠️ 移动后会发生什么?
移动后:
- 被移动的对象 仍然有效。
- 但其 内容未定义 —— 你只能销毁它或重新赋值。
std::string x = "abc"; std::string y = std::move(x); // x 现在处于有效但未定义的状态 —— 不要再读取它!
🧠 对内建类型使用 std::move()
int x = 42; int y = std::move(x); // 实际是拷贝,因为 int 没有移动语义
这没必要,因为像 int
这样的基本类型不支持移动构造。
🛠️ 自定义类型实现移动语义
class MyBuffer { int* data; size_t size; public: MyBuffer(size_t s) : size(s), data(new int[s]) {} // 移动构造函数 MyBuffer(MyBuffer&& other) noexcept : data(other.data), size(other.size) { other.data = nullptr; other.size = 0; } // 移动赋值运算符 MyBuffer& operator=(MyBuffer&& other) noexcept { if (this != &other) { delete[] data; data = other.data; size = other.size; other.data = nullptr; other.size = 0; } return *this; } ~MyBuffer() { delete[] data; } };
使用示例:
MyBuffer a(1000); MyBuffer b = std::move(a); // 将 a 移动到 b
📦 std::move() 与智能指针
可以用 std::move来操作智能指针,比如 unique_ptr 或 shared_ptr:
#include <memory> std::unique_ptr<int> p1 = std::make_unique<int>(10); std::unique_ptr<int> p2 = std::move(p1); // p1 现在为空指针
🔁 std::shared_ptr 所有权转移
当你“转移所有权”给另一个 shared_ptr
时,你实际上是:
- 将控制块(用于跟踪引用计数)从一个
shared_ptr
移动到另一个。 - 原来的
shared_ptr
变为空(use_count() == 0
)。 - 总体引用计数不变(仍为 1,除非还有其他共享所有者)。
✅ 示例:通过 std::move() 转移所有权
#include <iostream> #include <memory> int main() { std::shared_ptr<int> p1 = std::make_shared<int>(42); std::cout << "p1 use_count: " << p1.use_count() << std::endl; // 1 std::shared_ptr<int> p2 = std::move(p1); // 转移所有权 std::cout << "p1 is " << (p1 ? "not null" : "null") << std::endl; // null std::cout << "p2 use_count: " << p2.use_count() << std::endl; // 1 }
🔍 重要区别:shared_ptr vs unique_ptr
指针类型 | 转移机制 | 允许拷贝 | 主要用途 |
---|---|---|---|
std::unique_ptr |
仅支持 std::move() |
❌ 不允许 | 独占资源所有权 |
std::shared_ptr |
std::move() 或拷贝 |
✅ 允许 | 共享资源所有权,引用计数 |
⚠️ 注意事项
- 你可以使用 move 来转移
shared_ptr
的所有权(源指针将变为空)。 - 你也可以拷贝
shared_ptr
来共享所有权(两个指针都有效,引用计数增加)。 - 只有在你明确希望原来的
shared_ptr
被置空时才使用std::move()
。
🔄 常见使用模式
函数返回值使用移动:
std::string get_name() { std::string name = "Alice"; return std::move(name); }
只有在你想强制进行移动(比如返回函数参数)时才使用 std::move()
。
🚫 不该使用 std::move() 的场景
1. ❌ 不要从还需要使用的变量移动:
std::string s = "test"; std::string t = std::move(s); std::cout << s; // 内容未定义
2. ❌ 不要对 const 对象使用 std::move():
const std::string s = "hi"; std::string t = std::move(s); // 实际是拷贝,因为移动构造<a href="https://justyy.com/archives/67736">函数</a>无法接收 const 参数
🧪 总结速查表
使用场景 | 是否使用 std::move() | 原因 |
---|---|---|
移动大型容器或字符串 | ✅ 是 | 高效转移内存或资源 |
移动智能指针 | ✅ 是 | 转移所有权 |
基本类型(如 int、bool) | 🚫 否 | 没有移动语义,等同于拷贝 |
const 对象 | 🚫 否 | 移动构造函数不接受 const |
临时变量 | 🚫 通常不需要 | 已经是右值了 |
✅ 最后小贴士
如果你不确定该不该用 std::move()
,问自己:
“我是否不再需要这个变量并打算把它交出去?”
如果答案是“是” → 那就用 std::move()
。
C/C++编程
- C++ 教程: 用std::move来移动所有权
- C++中的 const和constexpr 比较
- 简易教程: C++的智能指针
- C++ 编程练习题: 如何合并两个二叉树?
- C++ 编程练习题 - 找出第三大的数
- C++ 编程练习题 - 最多连续的 1
- C++ 编程练习题 - 左子树叶节点之和 (深度优先+广度优先+递归)
- C++ 编程练习题 - 最多水容器 (递归)
- C++的异步编程: std::future, std::async 和 std::promise
- C编程练习题: 翻转整数位
- C++编程练习题: 找出字符串的所有大小小组合
- C/C++ 中的内存管理器(堆与栈)
- C++编程练习题: 对两单向链表求和
英文:Tutorial on C++ std::move (Transfer Ownership)
本文一共 880 个汉字, 你数一下对不对.扫描二维码,分享本文到微信朋友圈
The post C++ 教程: 用std::move来移动所有权 first appeared on 小赖子的英国生活和资讯.
相关文章:
- 简易教程: C++的智能指针 C++ 智能指针教程 C++ 中的智能指针提供了自动且安全的内存管理。它们通过 RAII(资源获取即初始化)机制,帮助开发者避免内存泄漏和悬空指针的问题,确保对象在生命周期结束时被正确释放。 本教程将介绍 C++ 中三种主要的智能指针: std::unique_ptr:独占式所有权 std::shared_ptr:共享式所有权 std::weak_ptr:非拥有式弱引用 1. std::unique_ptr unique_ptr 拥有独占所有权。一个资源只能被一个...
- 借助AI快速开源了三个小工具: 写代码越来越像做产品了, AI 真把我宠坏了(Vibe Coding) 程序员的未来?Vibe Coding + AI 一起上! 借助 AI 快速开源了三个小工具 最近,我利用 ChatGPT-4o 和 o4-mini 快速开发并开源了三个小工具。起因其实很简单——每次想转换 YAML/JSON 或进行...
- 被动收入之: 微博红包 今年开始重新经营我的微博帐号 drlai 收到两笔微信红包,应该是来自于官方的支持,150元(成功提现到支付宝)。虽然这不能持久,也没多少,但毕竟实现了零的突破,意义重大。 如果流量上来,内容创作者可能会接受到比较多的赞赏,这也是一个比较简单的变现方法。这也能作为一种被动收入,不过如果不是头部网红,可能杯水车薪,但如果你有好几个类似这样的,也能积少成多! 在用户中心,微博用户可以每天登陆手机微博APP打卡,获取点数和少量的红包钱(几分钱),积少成多! 微博做些小任务可获得积分和几分钱。聊胜于无。 微博的主要盈利模式 微博的主要盈利模式主要包括以下几个方面: 广告收入:微博的大部分收入来源于广告,尤其是品牌广告和效果广告。广告形式包括信息流广告(类似于推文广告)、热门话题广告、开屏广告和视频广告。品牌和企业可以利用微博庞大的用户群和社交互动来提升曝光率、推广品牌和产品。 会员服务:微博提供的VIP会员服务,用户可以支付订阅费用来享受更多的特权,比如个性化的主题、特有的表情包、私密权限设置等。这些会员服务主要面向个人用户,提升其社交体验。 直播和打赏:微博提供直播平台,用户可以通过购买虚拟礼物来支持主播,微博会从这些打赏中抽取一定比例的分成。此外,微博与内容创作者分成,通过内容付费、知识付费等形式变现。 增值服务:针对企业和大V(拥有大量粉丝的用户),微博还提供增值服务,如账号认证、粉丝数据分析、精准推送、推广和营销工具等。这些服务帮助企业提升营销效果,同时也增加了微博的收入来源。 电商和导流:微博上有大量的电商导流业务,尤其是和明星、网红的合作推广。微博用户在浏览社交内容时,可以直接跳转到商品购买链接,微博通过这种方式赚取导流佣金。 游戏联运:微博也会与一些游戏公司合作推出联合运营的游戏,微博负责推广和流量引入,用户充值或付费时,微博可以获得一部分的分成。 这些模式相结合,使得微博能够在广告市场、内容创作和电商等多个领域获利。...
- 步步高学生电脑上 Basic 编程语言 peek 用法示例 步步高学生电脑 是8位FC机的经典之作.它上面的BASIC有三个版本 1.0, 2.0 和 2.1 2.1 版本有个在线帮助,实际上是 help.cmd 1.0 是用 Esc 键退回到 DOS 的,...
- 换了个奥迪Q5大灯花了我1000英镑 我那辆奥迪Q5 SUV今年年检没通过,原因是左前车灯坏了,需要更换。车厂告诉我,光是订购零件就要700多英镑,加上人工费,总费用得1000英镑。但没办法,如果不修,车辆年检(MOT)就过不了,车也不能上路。 MOT是英国的机动车强制性安全检测(Ministry of Transport Test)的简称。 近侧前位置灯不工作 drl/位置灯集成(4.2.1(a)(ii)) Nearside Front Position lamp not working drl/position...
- C++ Ranges 教程 C++20 引入了 ranges(范围),这是一个强大且优雅的抽象,用于处理序列(如数组、vector 等)。相比传统的迭代器或旧式循环,Ranges 提高了代码的可读性、可组合性和性能。 什么是 Range? 在 C++20 中,range(范围) 是一种抽象,代表一个可以迭代的元素序列。它与 views(视图) 和 actions(操作) 如过滤、转换等配合使用非常自然。...
- C++中的 const和constexpr 比较 C++ const 与 constexpr:真正的区别是什么? 一眼看都是定义常量。 为什么这很重要 现代 C++ 鼓励编写不可变、高效且表达力强的代码。两个关键字—const 和 constexpr—是这一理念的核心。它们看起来很相似,但理解它们的不同语义,对于正确利用编译期与运行期行为至关重要。 高层次对比 特性 const constexpr...
- 你给SteemIt中文微信群拖后腿了么? 这年头不缺算法, 就缺数据. 这两天花了很多时间在整API上, 整完之后自己用了一下还觉得真是挺方便的. 今天就突然想看一看自己是否给大家拖后腿了, 于是调用每日中文区微信群排行榜单的API, 刷刷拿着 NodeJs 练手: 1 2 3 4 5 6...