当前位置: 首页 > 知识库问答 >
问题:

重新调整大小时,std::向量复制/移动元素吗?

宋凌龙
2023-03-14

我在学习/更新练习中摆弄移动计算器时,遇到了一些意想不到的事情。下面我有一个类< code>person,它包含一个< code > STD::string m _ name;。我用这个作为复制/移动连接器的测试类。

以下是快速参考的代码:

#include <iostream>
#include <vector>

class person
{
public:
    std::string m_name;
    explicit person(const std::string &name) : m_name(name)
    {
        std::cout << "created " << m_name << std::endl;     
    }
    
    ~person()
    {
        std::cout << "destroyed " << m_name << std::endl;       
    }   
    
    person(const person &other) : m_name(other.m_name)
    {
        m_name += ".copied";
        std::cout << "copied " << other.m_name << " -> " << m_name << std::endl;
    }
    
    person(const person &&other) noexcept : m_name(std::move(other.m_name))
    {
        m_name += ".moved";
        std::cout << "moved " << other.m_name << " -> " << m_name << std::endl;
    }   
};

int main()
{
    std::vector<person> people;
    people.reserve(10);
    
    std::cout << "\ncopy bob (lvalue):" << std::endl;
    person bob{"bob"};
    people.push_back(bob);

    std::cout << "\nmove fred (lvalue):" << std::endl;
    person fred{"fred"};
    people.push_back(std::move(fred));

    std::cout << "\ntemp joe (rvalue):" << std::endl;
    people.push_back(person{"joe"});
    
    std::cout << "\nterminating:" << std::endl;
}

这给出了我所期望的输出(除了为什么std::string内容没有被“移动”之外)。):https://godbolt.org/z/-J_56i

然后我删除std::vector<code>reserve</code>,这样std::vector在添加元素时必须“增长”。现在我得到了一些我真的没想到的东西:https://godbolt.org/z/rS6-mj

现在我可以看到bob被复制,然后在fred被添加时移动,然后在joe被添加时再次移动。我的印象是std::向量在必须重新分配空间时“移动”。但是我认为它做了内存复制/移动,而不是逐个对象的复制/移动。我真的没想到它会调用移动构造函数。

现在,如果我删除move c'tor,我发现bob被复制了三次!:https://godbolt.org/z/_BxnvU这看起来效率很低。

从cplusplus.com:

push_back()

在末尾添加元素在vector的末尾,当前最后一个元素之后添加一个新元素。val的内容被复制(或移动)到新元素中。

这有效地将容器大小增加了1,如果且仅当新的向量大小超过当前向量容量时,这导致自动重新分配已分配的存储空间。

调整大小()

调整容器的大小,使其包含 n 个元素。

如果 n 小于当前容器大小,则内容将减少到其前 n 个元素,删除超出的元素(并销毁它们)。

如果n大于当前容器大小,则通过在末尾插入尽可能多的元素来扩展内容,以达到n的大小。如果指定了val,则将新元素初始化为val的副本,否则,它们将被值初始化。

如果n也大于当前容器容量,则会自动重新分配分配的存储空间。

请注意,此函数通过插入或擦除容器中的元素来更改容器的实际内容。

我猜它并没有真正描述“如何”进行重新分配,但是内存复制肯定是将向量移动到新分配的内存空间的最快方式?

那么,当添加std::vector而不是内存副本时,为什么要调用复制/移动连接器呢?

附带说明/问题:(任何可能这都应该是一个单独的问题):亲自移动c'或为什么移动fred-


共有1个答案

夏星阑
2023-03-14

如果它需要重新定位,类似于std::move(xold.begin(),xold.end(),xnew.begin)) 。它取决于值类型,向量通常会进行自己的内部放置。但如果它能移动,它就会移动。

移动构造函数

person(const person &&other) noexcept;

但有一个缺陷:other不应该是const,因为必须允许它更改other以窃取其资源。在此移动构造函数中

person(person&& other) noexcept : m_name(std::move(other.m_name)) {}

std::string自己的move构造函数将执行类似的操作:

string(string&& other) noexcept : 
    the_size(other.the_size),
    data_ptr(std::exchange(other.data_ptr, nullptr))
{}

还需要添加移动分配运算符:

person& operator=(person &&other) noexcept;

 类似资料:
  • 为了增强用户体验,CSS3 中新增了一个非常实用的 resize 属性,该属性允许用户通过拖动的方式来自由缩放元素的尺寸,在此之前要实现类似的效果还需要借助大量的 JavaScript 代码。resize 属性的语法格式如下: resize: none|both|horizontal|vertical; 语法说明如下: none:用户无法调整元素的尺寸; both:用户可调整元素的高度和宽度; h

  • 为什么在狭窄的屏幕上,父母比孩子小? 请参阅代码段。。。然后调整浏览器的大小(宽度方向),使其小于粉红色框。滚动条应该出现。在页面上向右滚动,注意绿色背景比粉色区域小,并且右侧有一个白点。 问题太少了: > 为什么会这样? 当浏览器调整大小时,我如何防止父div的绿色背景变得比粉红色框/div小,而不在父div(或其他任何地方)上设置显式宽度或使用? 这个问题有flexbox解决方案吗? 谢谢 托

  • 问题内容: A 在其文档中有这样的短语: 如果初始容量大于最大条目数除以负载因子,则将 不会 发生任何哈希操作。 请注意文档中说的是 rehash ,而不是 resize- 即使仅在调整大小时才会发生rehash;也就是说,当存储桶的内部尺寸变大两倍时。 当然提供了这样的构造函数,我们可以在其中定义此 初始容量 。 构造一个具有指定初始容量和默认负载因子(0.75)的空HashMap。 OK,看起

  • 在本例中不会窃取返回变量。有没有办法避免多余的副本? 这就是结果: 基于建议的新代码(不知道是否一直在同一个线程上询问,不知道这是否是我所期望的,我所做的这一切都是为了减少代码): 看到它在行动中的新结果

  • 问题内容: 和其他几个,但是没有什么不是我想要的。我想要的是将某些内容缩放到其大小的50%(当然,还要进行动画效果的过渡),然后将页面布局重新调整为该元素的新(可视)大小。默认情况下似乎发生的是该元素仍保留其在布局结构中的原始大小,并且仅通过关联的转换进行绘制。 基本上,我希望用户单击一个文本块(或其他内容),然后将该文本缩放到其大小的50%(或任何其他大小),并将其粘贴在下面的面板中以表明已被选

  • 这里是简单的Java问题。我制作了一个自定义的JSlider,它在用户移动滑块的最后一个位置绘制方块。我们重写paintcomponent并绘制相对于滑块大小的方块。当你正确地使用滑块时,一切工作都很好。但是,当你调整框架的大小时,问题就会发生。滑块变大,滑块调节器随之移动,但是我们放置的方块相对于滑块不移动。当我们调整框架大小时,我们应该从JSlider中使用哪个函数来重新绘制? 我试图将JSl

  • 问题内容: 我一直试图(徒劳地)建立一个页面,当我更改窗口大小时,其元素将重新调整大小。我可以在CSS中使用它来处理图像,但是没有问题,但是我似乎无法在文本上完成相同的操作,而且我不确定在CSS中是否有可能。而且我似乎找不到能完成此任务的jQuery脚本。 当用户调整窗口大小时,我实质上希望页面能够动态流畅地缩放,而无需用户调用页面缩放。通过css在我的img div上这可以正常工作,但对于文本则

  • 问题内容: 我有正在调整大小的内容,并且我希望有一个不会增加/缩小并且不属于可滚动内容的固定标题。如果没有足够的空间,则下面的内容可滚动。 内容外部包装器()具有,内部包装器具有。这里的思想过程是将div内的所有剩余空间填满,然后内部包装将占据的整个高度,如果溢出,则应滚动。 发生的事情是确实会填满该区域,但似乎它的内容决定了它的最小高度。 我怎样才能使它永远不会超出区域高度? 注意:我看了这个类