std::vector的move构造函数是否调用项的move构造器
Does the move constuctor of std::vector call the move constructor of the items
我写了以下代码来理解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 processVectornn" << endl;
processVector(std::move(vec));
}
由于我在调用processVecor时传递了向量的Rvalue引用,因此当函数参数对象形成时,实际应该调用的是std::向量的move构造函数。是这样吗?
因此,我希望vecor的move构造函数本身会调用PointerHolder类的move构造器。
但没有任何证据可以证实这一点。
你能澄清一下这种行为吗。std::vector的move构造函数不是反过来调用单个项的move构造器吗
否。注意,std::vector
的运动控制器的复杂性要求是恒定的。
复杂度
6) 常量。
这意味着std::vector
的移动构造函数不会对每个单独的元素执行移动操作,这将使复杂性成为线性的(就像复制构造函数一样)。该实现可以直接移动内部存储器来实现它
否。相反,它会用所有元素窃取整个内存块。既然你可以把所有东西都拿走,为什么还要麻烦移动里面的东西呢?
(如果提供的分配器与源向量的分配器不相等,则分配器扩展的移动构造函数将需要执行成员移动。)
否,在调用std::vector
的move构造函数时不需要移动元素。为了理解原因,我认为你应该有一个关于std::vector
如何实现的良好心理模型。(大多数实现看起来是这样的,只是它们需要一些更复杂的处理分配器)
那么什么是std::vector
在最简单的形式中,它有3个成员:
- 容量:(size_t)
- A大小:(size_t)
- 指向数据的指针(T*、std_unique_ptr、void*)
大小表示有多少元素在使用,容量表示有多少数据适合当前分配的数据。只有当您的新大小大于容量时,才需要重新分配数据。
分配的数据是未初始化的内存,在其中可以就地构造元素。
因此,考虑到这一点,实现向量的移动将是:
- 复制容量/大小
- 复制指针并在原始指针中设置为nullptr(行为与unique_ptr相同)
这样,新实例是完全有效的。旧的在valid but unspecified state
中。最后一个意思是:你可以在不破坏程序的情况下调用析构函数。对于矢量,您也可以调用clear
将其恢复到有效状态,或者调用operator=
。
给定这个模型,您可以很容易地解释所有运算符。只有移动任务有点复杂。
否。它不调用move构造函数。若要调用元素的move构造函数,您必须在推送到向量本身的同时调用std::move。
int main()
{
vector<PointerHolder> vec;
PointerHolder p1;
PointerHolder p2;
vec.push_back(std::move(p1));
vec.push_back(p2);
cout << "Calling processVectornn" << endl;
processVector(std::move(vec));
}
输出
名为的构造函数
名为的构造函数
移动名为的构造函数
名为的复制构造函数
调用processVector
如果我们正在查看标准(https://en.cppreference.com/w/cpp/container/vector/vector)它说,移动需要恒定的时间O(1)。
不管怎样,如果我们查看最常见的实现,std::vector是一个动态数组。动态数组首先为8个元素分配例如空间。如果我们需要9的空间,这个8乘以或增加一个特定的量,通常乘以1.44,2或类似的东西。
但关于移动方面:我们的成员变量是什么?我们如何移动它们?好吧,正如所提到的,动态数组只是指向第一个元素的指针,如果我们想移动结构,我们会将指针复制到另一个对象,并将旧指针设置为nullptr(或者NULL,如果你不关心nullptr的实现目的,那么nullptl显然是首选)。当然,像内部保存的大小(如果保存)这样的东西必须被复制,并且在旧对象中也必须设置为零(或者任何移动语义)。
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 为什么不调用移动构造函数?(默认情况下只有构造器,没有别的)
- 添加自定义析构函数时,Move 构造函数在派生类中消失
- 如何在构造器的成员初始值设定项列表中调用两个函数?
- C++ 初始化构造器初始值设定项列表中的模板数组
- std::映射,只有move构造函数可用
- 为什么我的代码中没有调用move构造函数
- std::转换move构造函数的模板专业化的变体
- 如何调用move构造函数
- 我可以将 std::move 与不提供 move 构造函数的类一起使用吗?
- 私人构造器和make_shared
- 父类有 26 个构造函数重载.如何在不复制+粘贴 26 个重载的情况下将一个小任务附加到所有构造器?
- 如何将INT参数放入C 中的Sigleton构造器中
- 错误:呼叫构造器的匹配函数无匹配功能
- 子类化 std::thread:构造器中可变参数模板函数的问题
- 为什么noexcept move构造函数在向量重新分配期间没有被调用
- 初始化向量<向量<mytype>>构造器中的成员
- C++ 复制构造器不调用基构造函数
- 为什么在声明析构函数时必须声明 copy & move 构造函数?
- std::vector的move构造函数是否调用项的move构造器