移动元素,而向量中的重新分配元素

发布于 2025-01-28 19:30:47 字数 1953 浏览 2 评论 0原文

我有以下代码:

#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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

献世佛 2025-02-04 19:30:47

这是由于std :: vector的存储的 Realocations
每次您push_back,如果容器的容量不够大,则有一个重新分配。它需要所有当前元素的副本/移动到较大的存储中。

这里有关于使用移动构造函数的讨论,当std :: vector增长:当向量生长时如何强制执行语义?

建议在那里添加noexcept将告知std :: vector使用Move Senantics(带有一些链接到CPPREFERY)。我确认在您在MSVC中的情况下是如此。

为了避免它,您可以使用 std :: vector :: vector ::储备 。它将为push_back s保留存储。

main中的循环之前添加以下行添加以下行:

vector.reserve(100u);

现在您会看到只能调用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 whenstd::vector grows: How to enforce move semantics when a vector grows?.

It is suggested there that adding noexcept will inform the std::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 the push_backs.

Add the following line before the loop in your main:

vector.reserve(100u);

Now you'll see that only move constructor is called, once for each push_back.

横笛休吹塞上声 2025-02-04 19:30:47

std :: vector需要更多的空间时,它会分配一个新数组,然后复制/将所有现有元素从旧数组移动到新数组。在您的示例中,当使用push_back并且旧向量的容量不足以容纳所有元素(旧 +新)时,可能会发生这种重新分配。

解决方案1 ​​
为了最大程度地减少此功能,请在将元素推向向量之前,请使用std :: vector :: recest()成员功能。这预先分配了所需的空间。

std::vector<Data> myVector;
myVector.reserve(100u);
for (size_t i = 0u; i < 100u; ++i) {
        myVector.push_back(Data{});
    }

解决方案2
或者,您可以创建向量具有特定大小的向量,例如:

std::vector<Data> myVector(100u); //create a vector of size 100 where all elements are default initialized

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 when push_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.

std::vector<Data> myVector;
myVector.reserve(100u);
for (size_t i = 0u; i < 100u; ++i) {
        myVector.push_back(Data{});
    }

Solution 2
Or you can create the vector to be of a particular size, like:

std::vector<Data> myVector(100u); //create a vector of size 100 where all elements are default initialized
深空失忆 2025-02-04 19:30:47

我不确定您的期望。我以这样的方式计算了您的输出:

$ foo | tr " " "\n" | sort | uniq -c
127 copy
227 ctr
100 move

您使用临时对象调用vector.push_back 100次。由于那是可移动的,它将被转发到vector.emplace_back,而反过来将对象的构造转发到“移动ctr”。 100个电话,100个“移动CTR”。这正是您应该期望的电话数量。

您唯一要问的是127个“复制CTR”的电话。那是坏的。他们的原因是,当您将元素推入向量时,必须调整存储空间的大小。由于您的班级缺乏移动分配运算符,因此必须在调整大小上复制对象。您应该添加
data&amp;操作员=(data&amp;&amp; rhs),因此可以移动元素。

您可以通过使矢量从一开始就足够大,可以完全避免调整大小:

vector.reserve(100);

I'm not sure what you expected. I counted your output like this:

$ foo | tr " " "\n" | sort | uniq -c
127 copy
227 ctr
100 move

You call vector.push_back 100 times with a temporary object. Since that is movable it gets forwarded to vector.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:

vector.reserve(100);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文