构造函数中的 C++ 通用引用和返回值优化 (rvo)

2023-11-27

为什么在具有通用引用参数的构造函数的类中不会发生右值优化?

http://coliru.stacked-crooked.com/a/672f10c129fe29a0

#include <iostream>

 template<class ...ArgsIn>
struct C {

  template<class ...Args>
  C(Args&& ... args) {std::cout << "Ctr\n";}        // rvo occurs without &&

  ~C(){std::cout << "Dstr\n";}
};

template<class ...Args> 
auto f(Args ... args) {
    int i = 1;
  return C<>(i, i, i);
}

int main() {
  auto obj = f();
}

Output:

Ctr
Ctr
Dstr
Ctr
Dstr
Dstr

我认为问题在于实例化

template<class ...Args>
C(Args&& ... args) {std::cout << "Ctr\n";}  

就语言而言,不是复制/移动构造函数,因此编译器不能忽略对它们的调用。从 §12.8 [class.copy]/p2-3 开始,添加了强调并省略了示例:

A 非模板构造函数上课X是一个复制构造函数,如果 它的第一个参数的类型X&, const X&, volatile X& or const volatile X&, 要么没有其他参数,要么全部 其他参数有默认参数(8.3.6)。

A 非模板构造函数上课X是一个移动构造函数,如果 它的第一个参数的类型X&&, const X&&, volatile X&&, or const volatile X&&,要么没有其他参数,要么全部 其他参数有默认参数(8.3.6)。

换句话说,作为模板的构造函数永远不能是复制或移动构造函数。

返回值优化是复制省略的一种特殊情况,描述为(§12.8 [class.copy]/p31):

当满足某些标准时,允许实施省略 类对象的复制/移动构造,即使构造函数 选择用于复制/移动操作和/或析构函数 对象有副作用。

这允许实现省略“复制/移动构造”;使用既不是复制构造函数也不是移动构造函数的东西构造对象不是“复制/移动构造”。

Because C有用户定义的析构函数,不会生成隐式移动构造函数。因此,重载决策将选择模板化构造函数Args推论为C,这比右值的隐式复制构造函数更匹配。但是,编译器无法省略对此构造函数的调用,因为它有副作用,并且既不是复制构造函数也不是移动构造函数。

如果模板化构造函数是

template<class ...Args>
C(Args ... args) {std::cout << "Ctr\n";} 

那么它不能被实例化Args = C生成一个复制构造函数,因为这会导致无限递归。标准中有一条特殊规则禁止此类构造函数和实例化(§12.8 [class.copy]/p6):

类的构造函数的声明X如果它是格式错误的 第一个参数的类型(可选 cv 限定)X以及 没有其他参数或者所有其他参数都有 默认参数。成员函数模板永远不会被实例化 产生这样的构造函数签名。

因此,在这种情况下,唯一可行的构造函数将是隐式定义的复制构造函数,并且可以省略对该构造函数的调用。

如果我们改为remove自定义析构函数来自C,并添加另一个类来跟踪C的析构函数被调用:

struct D {
    ~D() { std::cout << "D's Dstr\n"; }
};

template<class ...ArgsIn>
struct C {
  template<class ...Args>
  C(Args&& ... args) {std::cout << "Ctr\n";}
  D d;
};

我们只看到一个调用D的析构函数,表明只有一个C对象被构造。这里C的移动构造函数是通过重载决策隐式生成和选择的,您会看到 RVO 再次启动。

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

构造函数中的 C++ 通用引用和返回值优化 (rvo) 的相关文章

随机推荐

  • TLS 连接未正确终止

    我正在使用 BitBucket 我的服务器上安装了一个存储库 git clone https bitbucket org myproject git 我能够从我的服务器拉取和推送到 bitbucket org 存储库 现在 在过去的几天里
  • 在“本地”或“监视”窗口中查看对象会导致 Excel 崩溃

    在 Excel 中 当我运行一些代码并放置断点时 我可以查看局部窗口中的值 在本地窗口中 当我尝试为我创建的类展开对象时 Excel 崩溃并显示 Microsoft Office Excel 遇到问题 需要关闭 对于给您带来的不便 我们深表
  • 如何编辑/重置警报管理器?

    我设置了一个首选项屏幕 其中有一个列表首选项 允许用户选择通知他们的时间间隔 他们可以选择是否每 2 4 8 10 或 12 小时后通知他们 这是我的列表偏好
  • 依赖于其他 DLL 的插件 DLL

    我正在编写一个 DLL 来插入另一个 第 3 方 应用程序 该 DLL 将需要依赖于另一组 DLL 出于许可原因 我无法静态链接 我希望我的 DLL 可以 xcopy deployable 到任何目录 我也不想要求将此目录添加到路径中 如果
  • 是否有人在加载 Keras 保存的模型时遇到“AttributeError: 'str' object has no attribute 'decode'”

    训练后 我使用保存了 Keras 整个模型和仅权重 model save weights MODEL WEIGHTS and model save MODEL NAME 模型和重量已成功保存 没有错误 我可以简单地使用 model load
  • 为什么 Microsoft 不支持 OLE DB 连接到 SQL Azure?

    At the MSDN 网站它说 不支持使用 OLE DB 连接到 SQL Azure 网络上还有其他地方 人们报告在调整连接字符串中的服务器名称后 它对他们来说工作得很好 例如here and here 甚至 SQL Server 的An
  • Android 谷歌日历 API 在发布时不起作用

    我正在使用 google calendar api 从公共日历获取事件 在谷歌开发者控制台中 我创建了一个服务帐户密钥 json 我用它来在 android 代码中设置 GoogleCredential 如下所示 AssetManager
  • 使用 np.polyfit 在 3 维中拟合多项式

    我有一个数据数组 具有尺寸 N 3 对于某个整数N 指定 3D 空间中粒子的轨迹 即每个行条目都是 x y z 粒子的坐标 该轨迹平滑且简单 我希望能够对该数据拟合多项式 我可以用以下方法做到这一点 x y 坐标使用np polyfit i
  • 如何在 postgresql 中自动递增字母数字值?

    我在用 PostgreSQL 9 3 5 我有一个Table StackOverflowTable with columns SoId SoName SoDob 我想要一个Sequence generator对于列SoId这是一个字母数字值
  • UITableView 在 UIScrollView 内部时出现滚动问题

    我有一个 UIScrollView 带分页 我向其中添加了三个 UIView 每个 UIView 内部都有一个 UITableView 因此 用户应该能够水平滚动到他想要的页面 然后在相应的表格中垂直滚动 但是 某些表格不接收滚动手势 通常
  • 如何在具有跨平台兼容性的情况下强制 Git 提交中的行结尾一致

    在与使用不同操作系统的人一起工作时 我遇到了由于行结尾而导致的合并冲突问题 我在 Windows 上工作 我的同事在 Mac 上工作 当他推送更改时 有时他未处理的文件会在差异中显示为已更改 因为行结尾现在显示 M在每个文件上 这导致了合并
  • 使用 BeanDefinitionRegistryPostProcessor 创建 N 个 Bean

    我正在尝试创建N动态使用的bean数量BeanDefinitionRegistryPostProcessor 基于this问题 我选择使用BeanDefinitionRegistryPostProcessor对于我的用例 我在我的中定义了以
  • heroku 推送错误:“无法检测 rake 任务”

    我正在尝试部署一个基本应用程序 但它不起作用 使用 git push heroku master 我收到此错误消息 remote Could not detect rake tasks remote ensure you can run b
  • JPEG 字节顺序对编码有何影响?

    我目前正在做一个涉及图片的大项目 我遇到的大问题之一是图片的字节顺序 jpeg 更清楚 我一直认为在我们的现代世界中我们不必担心这个问题 但现在我不确定 我做什么 我向 IP 摄像机发出 HTTP 请求 摄像机返回给我一个字节数组 我使用以
  • 断言比较两个对象列表 C#

    我目前正在尝试学习如何使用单元测试 并且我已经创建了 3 个动物对象的实际列表和 3 个动物对象的预期列表 问题是如何断言检查列表是否相等 我尝试过 CollectionAssert AreEqual 和 Assert AreEqual 但
  • boost asio iostream - 如何获取本地IP地址

    这是我的问题 我正在使用 boost asio ip tcp iostream 连接到服务器 boost asio ip tcp iostream s IP 1237 现在我想检索我自己的本地 IP 地址 我在谷歌深处找到了如何使用sock
  • Mayavi 可以渲染透明背景的人物场景吗?

    我正在使用 mayavi mlab 生成网格图 并希望背景不透明度为 0 或透明 这可能吗 如果您的目标是将 mayavi 图集成到 matplotlib 图中 这是可能的 您可以使用mlab screenshot获取 RGBA 值的 nu
  • 如何使用CSS组合混合混合模式和隔离?

    我有一个带有红色背景的父元素 我想要一个 h2 元素将一些单词与背景混合 其他单词在 span 标签内 不 我下面的例子不起作用 如何让它发挥作用 bg red background red blend mix blend mode dif
  • 结束日期大于开始日期验证android

    我有两个 EditText 一个带有开始日期 另一个带有结束日期 我需要进行验证并检查结束日期是否大于开始日期 我不知道我该怎么做 在我的代码中 我以天为单位计算两个日期之间的差异 现在我还需要检查结束日期是否大于开始日期 这是我的代码 E
  • 构造函数中的 C++ 通用引用和返回值优化 (rvo)

    为什么在具有通用引用参数的构造函数的类中不会发生右值优化 http coliru stacked crooked com a 672f10c129fe29a0 include