为什么 move 返回一个右值引用参数需要用 std::move() 包装它?

2023-11-22

我正在阅读《Effective Modern C++ Item 25》,第 172 页,它有一个示例来演示,如果您想移动返回右值引用参数,则需要用 std::move(param) 包装它。由于参数本身始终是左值,如果没有 std::move(),它将被复制返回。

我不明白。如果 std::move(param) 只是将其传入的参数转换为右值引用,那么当 param 已经是右值引用时有什么区别?

就像下面的代码一样:

#include <string>
#include <iostream>
#include <utility>

template<typename T>
class TD;

class Widget {
public:
    explicit Widget(const std::string& name) : name(name) {
        std::cout << "Widget created with name: " << name << ".\n";
    }

    Widget(const Widget& w) : name(w.name) {
        std::cout << "Widget " << name << " just got copied.\n";
    }

    Widget(Widget&& w) : name(std::move(w.name)) {
        std::cout << "Widget " << name << " just got moved.\n";
    }

private:
    std::string name;
};

Widget passThroughMove(Widget&& w) {
    // TD<decltype(w)> wType;
    // TD<decltype(std::move(w))> mwType;
    return std::move(w);
}

Widget passThrough(Widget&& w) {
    return w;
}

int main() {
    Widget w1("w1");
    Widget w2("w2");

    Widget wt1 = passThroughMove(std::move(w1));
    Widget wt2 = passThrough(std::move(w2));

    return 0;
}

它输出:

Widget created with name: w1.
Widget created with name: w2.
Widget w1 just got moved.
Widget w2 just got copied.

在 passThroughMove(Widget&& w) 中,w 的类型已经是右值引用,std::move(w) 只是再次将其转换为右值引用。如果我取消注释 TD 行,我可以看到 decltype(w) 和 decltype(std::move(w)) 都是 Widget &&:

move_parameter.cpp:27:21: error: implicit instantiation of undefined template 'TD<Widget &&>'
    TD<decltype(w)> wType;
                    ^
move_parameter.cpp:28:32: error: implicit instantiation of undefined template 'TD<Widget &&>'
    TD<decltype(std::move(w))> mwType;
                               ^

由于 w 和 std::move(w) 都是相同的右值引用类型,为什么“return std::move(w)”会移动 w,而“return w”只会复制?

编辑:感谢您的回答和评论。现在我有了更好的理解,但不确定它是否准确。所以 std::move(w) 返回一个右值引用,就像 w 本身一样。但 std::move(w) 作为函数调用,它本身就是一个右值,因此可以移动。而 w 作为一个命名变量,它本身就是一个左值,尽管它的类型是右值引用,所以它不能被移动。


表达式的类型与变量的类型不同,并且decltype两者都做。

decltype(w)

是变量w。

decltype((w))

是表达式的类型w (well (w)但那些是相同的)。

如果你有一个类型的变量foo&&,当在表达式中使用时,其类型为foo&——它被命名了,因此是一个左值。

这有一定道理。foo&&只是意味着它可以绑定到临时的。一旦绑定,它就有一个名称并且可以多次使用。

任何可以多次使用的东西都不应该被隐式移出。

命名事物是左值这一规则的唯一例外是返回规则的隐式移动。在某些情况下,会发生省略但由于某种原因被阻止,值会被隐式移动。这些例外情况在此不适用。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 move 返回一个右值引用参数需要用 std::move() 包装它? 的相关文章

  • X11 模式对话框

    如何使用 Xlib 在 X11 中创建模式对话框 模态对话框是一个位于应用程序其他窗口之上的窗口 就像瞬态窗口一样 并且拒绝将焦点给予应用程序的其他窗口 在 Windows 中 当试图从模态窗口夺取焦点时 模态也会通过闪 烁模态窗口的标题栏
  • 结构体如何存储在内存中?

    我有一个struct iof header在我的代码中 我确定它的宽度是 24 字节 我执行 sizeof iof header 它返回 32 字节宽 问题1为什么是 32 字节宽而不是 24 字节宽 问题2包括其成员在内 结构体如何存储在
  • 如何在特定时间以毫秒精度触发 C# 函数?

    我有两台计算机 它们的时间通过 NTP 同步 确保时间仅相差几毫秒 其中一台计算机将通过 TCP 向另一台计算机发送一条消息 以在两台计算机上的未来指定时间启动某个 c 函数 我的问题是 如何在特定时间以毫秒精度 或更好 触发 C 中的函数
  • 将字符串作为 PChar 从 CSharp 传递到 Delphi DLL

    我正在尝试将字符串从 C 传递到 Delphi 构建的 DLL Delphi DLL 需要 PChar 这是Delphi导出 procedure DLL Message Location PChar AIntValue integer st
  • 为什么子函数不销毁GtkWindow?

    这是我的代码 void window first void enter window2 GtkWidget w gpointer data void quit GtkWidget w gpointer data void quit int
  • 如何从 Qt 应用程序通过 ODBC 连接到 MySQL 数据库?

    我有一个新安装的 MySQL 服务器 它监听 localhost 3306 从 Qt 应用程序连接到它的正确方法是什么 原来我需要将MySQL添加到ODBC数据源 我在遵循这个视频教程后做到了这一点 https youtu be K3GZi
  • 如何在C中同时运行两个子进程?

    所以我开始学习并发编程 但由于某种原因我什至无法掌握基础知识 我有一个名为 fork c 的文件 其中包含一个 main 方法 在此方法中 我将 main 分叉两次 分别进入子进程 1 和 2 在孩子 1 中 我打印了字符 A 50 次 在
  • opencv中如何去除二值图像噪声?

    将图像转换为二值图像 黑白 后如果有任何噪音怎么办 我消除了那些不需要的噪音 您可以看到下图的黑色区域内有一些白噪声 我该如何去除噪声 使用opencv http img857 imageshack us img857 999 blackn
  • C# 枚举到字符串自动转换?

    是否可以让编译器自动将我的 Enum 值转换为字符串 这样我就可以避免每次都显式调用 ToString 方法 这是我想做的一个例子 enum Rank A B C Rank myRank Rank A string myString Ran
  • 应用程序处于中断模式。您的应用程序已进入中断状态,

    我发现自己遇到了同样的问题here https stackoverflow com questions 36204009 disable break mode page in vs2015 我在 dll 中使用 Windows 窗体 这是针
  • 如何让XmlReader读取C#中的属性?

    我有一个 XML Stream 其中包含以下 XML 内容
  • 我可以将 UseCSharpNullComparisonBehavior 用于单个查询吗?

    我有一个查询 该查询曾经是存储过程 现已转换为 EF 查询 现在已经超时了 使用 SQL Profiler 我可以看到生成的 SQL 的唯一区别是 EF 转变的新行为entity Property value into entity Pro
  • 配置:错误:无法运行C编译的程序

    我正在尝试使用 Debian Wheezy 操作系统在我的 Raspberry Pi 上安装不同的软件 当我运行尝试配置软件时 我尝试安装我得到此输出 checking for C compiler default output file
  • 使用数据绑定,如何将包含表情符号的文本绑定到标签并使其正确显示?

    我正在编写一个应用程序来连接 WordPress BuddyPress API 该应用程序将允许用户通过 API 相互发送消息 当这些消息包含表情符号时 我很难正确显示它们 以下是 API 返回的消息文本的简短示例 Hi x1f642 ho
  • 如何检测应用程序正在运行的 .NET 版本?

    我尝试使用Environment Version ToString 确定目标计算机上正在使用什么 NET 框架 但安装了 4 0 版本时 它说我正在使用 NET 2 0 如何检测目标计算机上正在运行的 NET Framework 版本 En
  • Xcode 7 调试器不会中断内联标头函数

    过去五年我一直在各种 C 项目中使用 Xcode 没有出现这个问题 今天 我打开了一个较旧的项目 大约 2 年前 并尝试通过在该函数中放置一个活动断点来调试头文件中的内联函数 由于某种原因 调试器不会中断此代码 但是 如果我在调用该函数的
  • 卸载程序

    我正在尝试使用此代码卸载程序 但它似乎不起作用 我尝试过其他答案 但似乎也不起作用 有人可以帮助我吗 我正在尝试按给定名称 displayName 卸载该程序 例如 我给出 displayName Appname 那么此代码应该从我的计算机
  • Boost.asio和异步链,unique_ptr?

    我对异步编程不太熟悉 我有一个问题 我的问题如下 给出 boost asio 中 C 11 的 echo server 示例 http www boost org doc libs 1 60 0 doc html boost asio ex
  • 如何在 C 中创建最低有效位设置为 1 的掩码

    这个功能如何运作 最低有效 n 位设置为 1 的掩码 Example n 6 gt 0x2F n 17 gt 0x1FFFF 我根本不明白这些 尤其是 n 6 gt 0x2F 另外 什么是面膜 通常的方法是采取1 并将其左移n位 这会给你类
  • 在windows + opengl中选择图形设备

    我知道如何使用 openGL 打开窗口 使用 Win32 或其他工具包 但是当系统有2块显卡时 如何选择要渲染的图形设备 我的编程语言是 C 我专注于 Windows 但任何示例都将受到欢迎 编辑 也许更好地解释我的问题是个好主意 以便添加

随机推荐

  • 在 Linux 上使用 Mono 运行 SignalR .Net 客户端 - 可能吗?

    有谁有运行经验SignalR net 客户端在单声道上 我正在考虑将其用于需要运行跨平台的进程 需要连接到互联网托管的 SignalR Hub 我创建了一个在 mono 框架下使用 signalr 客户端工作的示例项目 https gith
  • PHP访问控制系统

    我是使用 PHP 和 MySQL 创建 Web 应用程序的团队的一员 该应用程序将有多个具有不同角色的用户 该应用程序还将以地理分布的方式使用 因此 我们需要创建一个在以下两个级别运行的访问控制系统 控制特定 php 页面的用户权限 即根据
  • 三次贝塞尔曲线上的最近点?

    如何沿着三次贝塞尔曲线找到最接近平面上任意点 P 的点 B t 我编写了一些快速而简单的代码来估计任意阶贝塞尔曲线的这一点 注意 这是伪暴力 而不是封闭式解决方案 Demo http phrogz net svg closest point
  • 使用 EclipseLink MOXy (JAXB) 将子类编组为 JSON 时是否可以隐藏“@type”条目?

    我即将开发一个基于 JAX RS 的 RESTful Web 服务 并使用 MOXy JAXB 来自动生成 Web 服务的 JSON 响应 一切都很酷 但由于 Web 服务将是基于 JavaScript 的 Web 应用程序的后端 因此可以
  • 具有提升权限的 CreateProcessAsUser

    我的服务在本地系统权限下运行 需要在用户会话中启动具有管理员权限的应用程序 我得到的是 WTSGetActiveConsoleSessionID WTSQueryUserToken用于会话 ID CreateProcessAsUser 问题
  • 让 Discord Bot 在 repl.it 上保持在线

    我该如何使用repl it对于我的 Python Discord Bot 并保持其 24 7 运行 我以前用过keep alive但由于某种原因它停止工作 有没有人有什么建议 我不断在控制台中收到此错误 172 18 0 1 2019 年
  • Python 的 site-packages 目录是什么?

    目录site packages在各种Python相关文章中都提到过 它是什么 我该如何使用它 site packages is the 目标目录手动构建的 Python 包 当您从源代码构建并安装 Python 包时 使用迪斯图尔斯 可能通
  • 如何从 Visual Code 中的快速打开菜单打开多个文件?

    我想知道是否可以从 Visual Code 中的快速打开菜单中打开多个文件 使用cmd p默认快捷方式 如果能够选择结果中的前 N 个文件并立即打开它们 将会很有帮助 例如 我可以输入 test device js 并且可以打开前 3 个文
  • Prolog 中的幂函数

    我的电源功能出了什么问题 pow 0 1 pow X Y Z pow X Y 1 X Z pow 2 3 Z ERROR Out of global stack 你的 Y 不会递减 你不能使用像函数这样的谓词 您还必须将 Z 与乘法结果统一
  • 如何在Django的同一页面上插入2个不同的表单

    我必须在同一页面中插入两个表单 1 登记表 2 登录表格 所以如果我在views py中使用它 if request method POST form registrationForm request POST if form is val
  • 不可变类和子类

    我正在尝试了解可变 不可变类 我遇到了这个帖子 提供的部分答案是 如果你想强制不变性 你就不能有子类 看 例如 java lang String 由于这个原因它是最终类 防止人们对 String 进行子类化以使其可变 好吧我明白了but 你
  • 在 Java 中 Jackson JSON 反序列化期间忽略丢失的属性

    在示例中 class Person String name int age 如果 JSON 对象缺少属性 age name John Person person objectMapper readValue jsonFileReader P
  • 可以授予一台计算机上的“网络服务”对另一台计算机上的目录的权限吗?

    我有一个文件 Computer1 Share file pdf 我需要使用在另一台计算机上作为网络服务帐户运行的服务来打开 Computer2 NETWORK SERVICE FWIW 两者Computer1 and Computer2位于
  • 在除一侧之外的所有侧面上创建 CSS3 框阴影

    我有一个选项卡式导航栏 我希望打开的选项卡有一个阴影 以将其与其他选项卡区分开来 我还希望整个选项卡部分有一个向上的阴影 参见底部水平线 遮蔽除打开的选项卡之外的所有选项卡的底部 我将使用 CSS3box shadow财产来做到这一点 但我
  • 在 ASP.NET 页面中包含脚本的正确方法

    我有一个 ASP NET 应用程序 它混合使用了由不同背景的几位开发人员编写的 ASP NET AJAX 包括 UpdatePanel 和 jQuery 一些包含在 ScriptManager 本身中的脚本
  • PHP 如何将标题定位到父目录中的页面?

    我有一个first php页面与 header Location script script1 php and script1 php还有另一个 header Location first php 但这显然让我 script first p
  • 使用 ACTION_SEND 共享文本文件

    我们可以使用 ACTION SEND 打开共享对话框来共享文本 Intent sendIntent new Intent sendIntent setAction Intent ACTION SEND sendIntent putExtra
  • Xcode -dynamic 未指定静态库错误

    我在 Xcode 中有一个子项目 它创建一个由父项目引用的静态库 一切都很好 直到 iOS 7 1 和 Xcode 5 1 发布 突然我收到以下警告 Applications Xcode app Contents Developer Too
  • 在 PHP 中解析时取消货币格式

    有没有办法获取字符串的浮点值 如下所示 75 25 以外parsefloat str replace var 我希望这取决于当前的站点语言 有时逗号可以用点代替 这是一个稍微复杂 缓慢的解决方案 但适用于所有区域设置 rlenom 的解决方
  • 为什么 move 返回一个右值引用参数需要用 std::move() 包装它?

    我正在阅读 Effective Modern C Item 25 第 172 页 它有一个示例来演示 如果您想移动返回右值引用参数 则需要用 std move param 包装它 由于参数本身始终是左值 如果没有 std move 它将被复