首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在C++中,如何预测是否会调用移动或复制语义?

在C++中,如何预测是否会调用移动或复制语义?
EN

Stack Overflow用户
提问于 2018-08-24 14:32:49
回答 1查看 66关注 0票数 2

考虑到C++编译器在实例化临时对象和调用返回值优化等机制方面的灵活性,通过查看一些代码并不总是清楚是否会调用移动或复制语义(或者调用多少)。

几乎感觉这些原语是为附带优化而存在的。也就是说,你可能会得到它们,也可能得不到。当很难控制moves本身的调用时,似乎很难设计任何一种利用moves的资源管理策略。

有没有一种方法可以清楚地(简单地)预测在某些代码中可能发生的复制和移动的位置和数量?理想情况下,不需要是编译器内部的专家就能做到这一点。

EN

回答 1

Stack Overflow用户

发布于 2018-08-24 15:17:10

似乎很难设计任何一种利用移动的资源管理策略,因为很难控制移动本身的调用。

我要反驳这一点。在设计资源处理类时,利用移动语义应该独立于客户端代码中如何或何时发生复制或移动构造。一旦有了move-ctor/assignment,就可以设计客户端代码来利用这些特殊成员函数的存在。

有没有一种方法可以清楚地(简单地)预测某些代码中可能发生的复制和移动的位置和数量?

很难简单地说出这里的意思,但我是这样理解的:

  • 假设一个类没有移动运算符/赋值运算符,你总是会得到一个副本。这是微不足道的,但在处理遗留代码中具有用户定义的析构函数和/或复制函数/赋值的类时,请记住这一点很重要,因为编译器在这种情况下不会生成移动函数/赋值。
  • 返回值优化。这个问题被标记为C++11,所以你不能保证使用C++17带来的pr值进行初始化时的副本省略。然而,可以公平地假设你的编译器已经实现了相同的机制。因此,

struct A{};A func() { return A {};}

可以假定构造A的实例,函数返回值在调用端绑定到该实例。这既不会导致移动,也不会导致复制构造。如果返回的对象有名称,则可以乐观地假设相同的行为,只要func()没有使NRVO变得不可能的分支。

作为该准则的一个例外,同时也是函数参数的函数返回值不符合返回值优化的条件。因此,在A是可移动构造的情况下,移动/转发它们以防止复制:

A func(A& a) { return std::move(a);}

因此,由func(A&)的返回值创建的对象将是move-constructed.

  • Function参数,它不会揭示它们本身的行为,它取决于类型及其特殊的成员函数。给定的

void f1(A a1) {A a2{std::move( a1) };};void f2(A& a1){ /*同上。*/ };void f1(A&& a1) { /*再次,相同。*/ };

如果A具有移动函数,则实例a2是移动构造的,否则为copy。

除了上面的范例案例之外,还有很多需要发现的地方,我既不能深入到更多的细节,也不能满足答案的简单性。此外,当您不知道您正在处理的类型时,场景也会有所不同,例如在函数或类模板中。在这种情况下,关于如何处理复制或移动的相关不确定性的很好的读物是Eff中的第29项。现代C++ (“假设移动操作不存在,不便宜,不使用”)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51998723

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档