2

我已经阅读了下面的帖子,它很好地了解了移动语义:

有人可以向我解释一下移动语义吗?

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

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

  2. 即使我们的类没有移动构造函数,但 STL 容器有一个。对于像这样的操作

std::vector<MyClass> vt = CreateMyClassVector();

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

3. 在以下情况下,我们是否受益于移动语义 -

std::vector< int > vt1(1000000, 5); // Create and initialize 1 million entries with value 5

std::vector< int > vt2(std::move(vt1)); // move vt1 to vt2

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

4. 当使用 std::move 左值调用 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 连续内存区域,在这种情况下不移动内存与复制内存一样好,移动如何证明通过简单地移动指向堆的不同区域中的内存的指针来向量连续的内存需求。?

感谢您提前解释!

[最初发布为移动语义澄清,但现在随着上下文的变化,将其发布为新问题应尽快删除旧问题。]

4

2 回答 2

2

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

是的,RVO 仍然起作用。实际上,编译器应该选择:

  • RVO(如果可能)
  • 移动施工(如果可能)
  • 复制构造(最后的手段)

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

STL 容器可移动的,与存储在其中的类型无关。然而,对容器中对象的操作需要对象的合作,因此排序(例如)只能在对象是可移动的情况下移动对象。

在以下情况下,我们是否会从移动语义中受益[...],因为整数是原始类型?

是的,你这样做了,因为容器无论其内容如何都是可移动的。正如您推断的那样,st2将从中窃取内存st1。移动后的状态st1是未指定的,所以我不能保证它的存储会被取消。

push_back()使用左值调用astd::move时 [会发生什么]?

调用左值类型的移动构造函数,通常这涉及将原件按位复制到目的地,然后将原件无效。

一般来说,移动构造函数的成本与sizeof(object); 例如,sizeof(std::string)无论有多少字符,它都是稳定的std::string,因为实际上这些字符存储在堆上(至少当它们有足够数量时),因此只有指向堆存储的指针被移动(加上一些元数据)。

于 2013-01-31T10:24:13.227 回答
1
  1. 是的。
  2. 他们尽可能地这样做。
  3. 是的。std::vector有一个移动构造函数,可以避免复制所有元素。
  4. 它仍然是连续的。

例如

struct MyClass
{         
     MyClass(MyClass&& other) 
         : xs(other.xs), size(other.size)
     {
          other.xs = nullptr;
     }

     MyClass(const MyClass& other) 
       : xs(new int[other.size]), size(other.size)
     { 
         memcpy(xs, other.xs, size);
     }

     ~MyClass() 
     {               
         delete[] xs;
     }

     int* xs;
     int size;
}

仅使用移动构造函数xs并且size需要复制到向量中(用于连续内存),但是我们不需要执行内存分配,memcpy就像在复制构造函数中一样。

于 2013-01-31T06:33:50.040 回答