为什么复制和移动构造函数最终使用相同数量的内存副本?

问题描述 投票:0回答:1

这里的问题是要了解通过函数的返回对象初始化向量时是否调用了复制或移动构造函数。在两种情况下,使用探查器检查malloc都会显示相似的内存副本。为什么?

我们有一类“消息”。该类提供一个函数“ data_copy”,该函数以向量形式返回“消息”的内容。

我尝试了2个选项。一种是直接使用复制构造函数来初始化新向量。

std::vector<uint8_t> vector1 ( message.data_copy() );

第二个选择是尝试避免多余的复制并执行

std::vector<uint8_t> vector1 ( std::move( message.data_copy() ) );

作为参考,我附上data_copy()的作用。

std::vector<uint8_t> message::data_copy(void) const
{
    std::vector<uint8_t> d(this->size());
    copy_data_to_buffer(d.data());
    return d;
}
void message::copy_data_to_buffer(uint8_t* buffer) const
{
    DEBUG_LOG("copy_data_to_buffer");
    for(const fragment* p = &head; p != nullptr; p = p->next)
    {
        memcpy(buffer, p->data[0], p->size[0]);
        buffer += p->size[0];

        if(p->size[1])
        {
            memcpy(buffer, p->data[1], p->size[1]);
            buffer += p->size[1];
        }
    }
}

最后,通过使用探查器,我比较了malloc调用的数量。尽管人们希望move构造函数实际上会避免多余的内存复制,但在两种情况下它们都是相同的。

c++ c++11 copy-constructor move-semantics move-constructor
1个回答
4
投票

您两次都使用了move构造函数。 data_copy的结果是临时的。然后,使用此临时参数构造vector。所以这是一个举动。

第二次,您基本上是将已经是右值引用的东西转换为右值引用,因此再次使用move构造函数。两者之间的行为绝对没有区别。

我认为,也许您误解了什么是临时的,什么是右值引用。 ::std::move并非经常使用,如果正在使用,则应仔细查看所使用的代码,以确保做正确的事。

此Godbolt上的代码为proof that the copy constructor is never called。这是链接到的代码:

#include <utility>

struct ICantBeCopied {
    ICantBeCopied(ICantBeCopied const &) = delete;
    ICantBeCopied(ICantBeCopied &&) {}
    ICantBeCopied() {}
};

ICantBeCopied make_a_copy()
{
    ICantBeCopied c;
    return c;
}

void a_function()
{
    ICantBeCopied a{make_a_copy()};
    ICantBeCopied b{::std::move(make_a_copy())};
}
© www.soinside.com 2019 - 2024. All rights reserved.