std :: vector的move构造函数是否调用项的move构造函数

时间:2018-12-21 04:11:39

标签: c++

我编写了以下代码来了解std :: vector的移动含义

class PointerHolder
{
public:

    PointerHolder()
    {
        cout << "Constructor called" << endl;
    }

    //copy constructor
    PointerHolder(const PointerHolder& rhs)
    {
        cout << "Copy Constructor called" << endl;
    }

    //copy assignment operator
    PointerHolder& operator = (const PointerHolder& rhs)
    {
        cout << "Copy Assignment Operator called" << endl;
        return *this;
    }

    // move constructor
    PointerHolder(PointerHolder&& rhs)
    {
        cout << "Move Constructor called" << endl;
    }

    // move assignment operator

    PointerHolder& operator = (PointerHolder&& rhs)
    {
        cout << "Move Assignment Operator called" << endl;
        return *this;
    }   
};

void processVector(std::vector<PointerHolder> vec)
{

}

int main()
{
   vector<PointerHolder> vec;
   PointerHolder p1;
   PointerHolder p2;

   vec.push_back(p1);
   vec.push_back(p2);

   cout << "Calling processVector\n\n" << endl;

   processVector(std::move(vec));

}

因为我在调用processVecor时传递了向量的Rvalue引用,所以实际上应该调用的是形成函数参数对象时std :: vector的move构造函数。是吗?

因此,我期望vecor本身的vecor的move构造函数将调用PointerHolder类的move构造函数。

但是没有证据表明这一点。

能否请您澄清一下行为。不会反过来调用std :: vector的move构造函数

5 个答案:

答案 0 :(得分:2)

不。请注意,move contructor of std::vector的复杂度要求是恒定的。

  

复杂度

     

6)恒定。

这意味着std::vector的移动构造器不会在每个元素上执行移动操作,这会使复杂度变为线性(例如复制构造函数)。该实现可以直接移动内部存储器来实现它。

答案 1 :(得分:2)

不。而是使用所有元素来窃取整个内存块。当您只需要抓住整个内容时,为什么还要麻烦移动内容?

(如果提供的分配器与源向量的分配器比较不相等,则分配器扩展的move构造函数将需要执行成员移动。)

答案 2 :(得分:0)

不。它不调用move构造函数。要调用element的move构造函数,您必须在推动向量自身的同时调用std :: move。

int main()
{
   vector<PointerHolder> vec;

   PointerHolder p1;
   PointerHolder p2;

   vec.push_back(std::move(p1));
   vec.push_back(p2);

   cout << "Calling processVector\n\n" << endl;

   processVector(std::move(vec));

}

输出

构造函数称为

构造函数称为

移动构造函数称为

复制构造函数称为

调用processVector

答案 3 :(得分:0)

如果我们正在查看标准(https://en.cppreference.com/w/cpp/container/vector/vector),它说,移动需要恒定的时间O(1)。

无论如何,如果我们查看最常见的实现,std :: vector是一个动态数组。例如,动态数组首先为8个元素分配空间。如果我们需要9的空间,则将这8乘以或增加特定的数量,通常乘以1.44、2或sth。这样。

但是关于移动方面:我们的成员变量是什么,以及如何移动它们?好吧,动态数组只是-如前所述-指向第一个元素的指针,如果我们想移动结构,我们将把该指针复制到另一个对象,并将旧指针设置为nullptr(如果您不在乎,则为NULL)对于已实现nullptr的问题,显然更可取的是nullptr)。当然,必须复制内部保存的大小(如果保存)之类的东西,并且在旧对象中也必须将其设置为零(或存在任何移动语义)。

答案 4 :(得分:0)

否,调用std::vector的move构造函数时不需要移动元素。要理解原因,我认为您应该对std::vector的实现方式有一个良好的思维模式。 (大多数实现看起来像这样,只是它们需要更多的复杂性来处理分配器)

std::vector是什么?

以最简单的形式,它具有3个成员:

  • 容量:(size_t)
  • 尺寸:(size_t)
  • 指向数据的指针(T *,std_unique_ptr,void *)

大小表示正在使用的元素数量,容量表示当前分配的数据中可以容纳多少数据。仅当您的新大小超过容量时,才需要重新分配数据。

分配的数据是未初始化的内存,在其中就可以构造元素。

因此,鉴于此,实现向量的移动将是:

  • 复制容量/大小
  • 复制指针并设置为原始的nullptr(与unique_ptr相同的行为)

这样,新实例完全有效。旧的位于valid but unspecified state中。这最后一个意思是:您可以调用析构函数而不会导致程序崩溃。 对于矢量,还可以调用clearoperator=将其恢复为有效状态。

使用此模型,您可以轻松解释所有运算符。只有移动分配要复杂一些。