我编写了以下代码来了解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构造函数
答案 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个成员:
大小表示正在使用的元素数量,容量表示当前分配的数据中可以容纳多少数据。仅当您的新大小超过容量时,才需要重新分配数据。
分配的数据是未初始化的内存,在其中就可以构造元素。
因此,鉴于此,实现向量的移动将是:
这样,新实例完全有效。旧的位于valid but unspecified state
中。这最后一个意思是:您可以调用析构函数而不会导致程序崩溃。
对于矢量,还可以调用clear
或operator=
将其恢复为有效状态。
使用此模型,您可以轻松解释所有运算符。只有移动分配要复杂一些。