【问题标题】:Move semantics clarification [duplicate]移动语义澄清[重复]
【发布时间】:2013-01-14 05:58:40
【问题描述】:

我已经阅读了下面的文章,它对移动语义有了很好的了解:

Can someone please explain move semantics to me?

但我仍然无法理解以下有关移动语义的内容 -

  1. 复制省略和 RVO 是否仍然适用于没有移动构造函数的类?

  2. 即使我们的类没有移动构造函数,但 STL 容器却有。对于像

  3. 这样的操作

std::vector vt = CreateMyClassVector();

并执行排序等操作。为什么 STL 不能在内部利用移动语义在内部使用不需要移动构造函数的复制省略或 RVO 等操作来改进此类操作?

3。 在以下情况下,我们是否会从移动语义中受益 -

std::vector vt1(1000000, 5); // 创建并初始化 100 万个值为 5 的条目

std::vector vt2(std::move(vt1)); // 移动 vt1 到 vt2

由于整数是原始类型,移动整数元素不会提供任何优势。 或者在移动操作之后 vt2 只是指向堆中的 vt1 内存,并且 vt1 设置为空。实际发生了什么?如果是后者,那么即使第 2 点也认为我们的类可能不需要移动构造函数。

4。 当使用 std::move on lvalue 调用 push_back() 时,例如:

    std::vector<MyClass> vt;

    for(int i=0; i<10; ++i)
    {
        vt.push_back(MyClass());
    }

    MyClass obj;

    vt.push_back(std::move(obj));

现在,由于向量具有连续的内存分配,并且 obj 在内存中的其他位置定义,移动语义如何将 obj 内存移动到向量 vt 连续内存区域,在这种情况下不移动内存与复制内存一样好,如何move 是否通过简单地移动指向堆不同区域中内存的指针来证明向量连续内存需求的合理性?

提前感谢您的解释! [按要求编辑问题。]

【问题讨论】:

  • 如果您使用指针,则无需使用move。你可以这样做 .push_back(obj_ptr); obj_ptr = nullptr; 在处理对象本身时使用移动语义。
  • 感谢 Bartek,我意识到并编辑了这个问题,尽管 MyClass 类可能有动态内存分配。
  • 另外,逗号不用于结束句子;请使用一些句号。
  • 好吧,再说一遍:如果 Obj 是一个 POD,那就和你说的完全一样——它必须被复制。但是想象一下,对象的唯一内容是指向缓冲区的指针及其大小。只有这两个会被 move 复制,而要执行完整复制,您必须复制缓冲区内容。
  • 但是指向缓冲区的指针不会落在不同的内存地址上,仅仅移动它可能无法满足向量所有元素的连续内存要求吗?

标签: c++ c++11 move-semantics


【解决方案1】:

大多数语义不是移动内存的方式。这完全是关于将对象的所有权从一个对象实例转移到另一个对象实例。当你这样做时:

std::string str1("Some string.");
std::string str2(std::move(str1));

std::string 分配和管理字符缓冲区。因此,每个std::string拥有一个内存缓冲区,其中包含字符串本身。

调用构造str2 的移动构造函数将获取str1 分配的字符缓冲区并将其从该对象中删除。因此str2 现在拥有str1 最初分配的指针,而str1 不再拥有该指针。这就是移动语义的全部内容:转移对象拥有的内存的所有权。

如果您的类没有移动构造函数,std::vector 将不会调用它。明显地。因此,它不能利用移动构造函数可能带来的任何潜在优化。但是这些优化机会存在于具有值语义并且包含必须管理的资源的对象。否则,运动对你没有帮助。

一般规则是使用智能指针和容器对象,如vectorstring 等,以避免编写移动构造函数。因此,(如果您的编译器正确支持生成移动构造函数)资源管理会自动发生。

【讨论】:

  • 谢谢,是的,我的班级没有移动构造函数,但 STL 容器有。所以说当我将一个填充有 MyClass 对象的向量 vt 复制到另一个向量 vt2 或执行排序等操作时。STL 不会在内部利用移动语义来改进此类操作吗?同样在上一段中,您提到一般的经验法则是使用智能指针和 STL 容器,但如果它们包含没有移动构造函数的用户定义类型,那么正如您所提到的,它们可能不会受益,不是吗?。
  • @Goku:不,因为您正在复制矢量。该向量将分配一个新缓冲区并将其每个对象复制到第二个向量中。如果向量是临时的(如表达式的返回值,或者在 v2 = std::move(v1) 的情况下),则 STL 将通过将整个缓冲区从 v1 移动到 v2 来利用,将 v1 留空。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-08-29
  • 1970-01-01
  • 2017-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-14
相关资源
最近更新 更多