这里的问题是了解在通过函数的返回对象初始化 vector 时是否调用了复制或 move 构造函数。 使用探查器检查 mallocs 在两种情况下显示相似的 memcopies。为什么?
我们有一个类型为“消息”的类。该类提供了一个函数“data_copy”,它将“消息”的内容作为 vector 返回。
我尝试了 2 个选项。 一种是直接使用复制构造函数来初始化一个新的vector。
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 构造函数在现实中避免额外的 memcopy,但它们在两种情况下都是相同的。
最佳答案
您两次都在使用 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())};
}
关于c++ - 为什么复制和 move 构造函数以相同数量的 memcopies 结束?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58599419/