移动元素,而向量中的重新分配元素
我有以下代码:
#include <vector>
#include <iostream>
struct Data
{
Data() = default;
Data(const Data& other)
{
std::cout << "copy ctr" << std::endl;
}
Data(Data&& other)
{
std::cout << "move ctr" << std::endl;
}
};
int main(int argc, char** argv)
{
std::vector<Data> vector;
for (size_t i = 0u; i < 100u; ++i) {
vector.push_back(Data{});
}
return EXIT_SUCCESS;
}
带有以下输出:
移动CTR 移动CTR 复制Ctr 移动CTR 复制Ctr 复制Ctr 移动CTR 移动CTR 复制Ctr 复制Ctr 复制Ctr 复制Ctr 移动CTR 移动CTR 移动CTR 移动CTR 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 复制Ctr 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR 移动CTR,
为什么我有这么多移动操作???
我的副本和移动构造函数并非没有...
I have the following code:
#include <vector>
#include <iostream>
struct Data
{
Data() = default;
Data(const Data& other)
{
std::cout << "copy ctr" << std::endl;
}
Data(Data&& other)
{
std::cout << "move ctr" << std::endl;
}
};
int main(int argc, char** argv)
{
std::vector<Data> vector;
for (size_t i = 0u; i < 100u; ++i) {
vector.push_back(Data{});
}
return EXIT_SUCCESS;
}
With the following output:
move ctr
move ctr
copy ctr
move ctr
copy ctr
copy ctr
move ctr
move ctr
copy ctr
copy ctr
copy ctr
copy ctr
move ctr
move ctr
move ctr
move ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
copy ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
move ctr
Why I have so much move operations???
My copy and move constructor aren't noexcept...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这是由于
std :: vector
的存储的 Realocations 。每次您
push_back
,如果容器的容量不够大,则有一个重新分配。它需要所有当前元素的副本/移动到较大的存储中。这里有关于使用移动构造函数的讨论,当
std :: vector
增长:当向量生长时如何强制执行语义?。建议在那里添加
noexcept
将告知std :: vector
使用Move Senantics(带有一些链接到CPPREFERY)。我确认在您在MSVC中的情况下是如此。为了避免它,您可以使用
std :: vector :: vector ::储备
。它将为push_back
s保留存储。在
main
中的循环之前添加以下行添加以下行:现在您会看到只能调用MOVE构造器,一次为每个
push_back
。This is due to reallocations of the storage for the
std::vector
.Each time you
push_back
, if the capacity of the container is not big enough, there's a reallocation. It requires a copy/move of all the current elements into the bigger storage.There's a discussion here about using move constructor when
std::vector
grows: How to enforce move semantics when a vector grows?.It is suggested there that adding
noexcept
will inform thestd::vector
to use move semantics (with some links to cppreference). I confirmed that is so in your case in MSVC.In order to avoid it you can use
std::vector::reserve
. It will reserve storage for thepush_back
s.Add the following line before the loop in your
main
:Now you'll see that only move constructor is called, once for each
push_back
.当
std :: vector
需要更多的空间时,它会分配一个新数组,然后复制/将所有现有元素从旧数组移动到新数组。在您的示例中,当使用push_back
并且旧向量的容量不足以容纳所有元素(旧 +新)时,可能会发生这种重新分配。解决方案1
为了最大程度地减少此功能,请在将元素推向向量之前,请使用
std :: vector :: recest()
成员功能。这预先分配了所需的空间。解决方案2
或者,您可以创建向量具有特定大小的向量,例如:
When
std::vector
needs more space, it allocates a new array and copies/moves all the existing elements from the old array to the new array. In your example, this reallocation may happen whenpush_back
is used and the capacity of the old vector is not enough to hold all the elements(old + new).Solution 1
To minimize this, use the
std::vector::reserve()
member function before pushing elements onto the vector. This pre-allocates the needed space.Solution 2
Or you can create the vector to be of a particular size, like:
我不确定您的期望。我以这样的方式计算了您的输出:
您使用临时对象调用
vector.push_back
100次。由于那是可移动的,它将被转发到vector.emplace_back
,而反过来将对象的构造转发到“移动ctr”。 100个电话,100个“移动CTR”。这正是您应该期望的电话数量。您唯一要问的是127个“复制CTR”的电话。那是坏的。他们的原因是,当您将元素推入向量时,必须调整存储空间的大小。由于您的班级缺乏移动分配运算符,因此必须在调整大小上复制对象。您应该添加
data&amp;操作员=(data&amp;&amp; rhs)
,因此可以移动元素。您可以通过使矢量从一开始就足够大,可以完全避免调整大小:
I'm not sure what you expected. I counted your output like this:
You call
vector.push_back
100 times with a temporary object. Since that is movable it gets forwarded tovector.emplace_back
which in turn forwards the construction of the objects to "move ctr". 100 calls, 100 "move ctr". That's exactly the number of calls you should expect.The only thing you should be asking about are the 127 calls to "copy ctr". Those are the bad ones. And the reason for them is that as you push elements into the vector it has to resize the storage. Since your class lacks a move assignment operator the objects have to be copied on resize. You should add
Data & operator=(Data &&rhs)
so elements can be moved.You can avoid the resize altogether by making the vector big enough from the start: