Pas*_* By 12 c++ string move-semantics
我正在调查搬家的表现std::string.在最长的时间里,我认为字符串移动几乎是免费的,认为编译器将内联所有内容,它只涉及一些廉价的任务.
事实上,我的移动心理模型是字面上的
string& operator=(string&& rhs) noexcept
{
swap(*this, rhs);
return *this;
}
friend void swap(string& x, string& y) noexcept
{
// for disposition only
unsigned char buf[sizeof(string)];
memcpy(buf, &x, sizeof(string));
memcpy(&x, &y, sizeof(string));
memcpy(&y, buf, sizeof(string));
}
Run Code Online (Sandbox Code Playgroud)
据我所知,如果将memcpy其更改为分配单个字段,则这是一个合法的实现.
我非常惊讶地发现gcc的移动实现涉及创建一个新的字符串,并且可能因为分配而可能抛出noexcept.
这甚至符合要求吗?同样重要的是,我不应该认为移动几乎是免费的吗?
令人眼花缭乱,std::vector<char>归结为我所期待的.
clang的实现有很大的不同,尽管存在疑问std::string::reserve
我只分析了GCC的版本。发生的事情是这样的:代码处理不同类型的分配器。_S_propagate_on_move_assign如果分配器具有或 的特征_S_always_equal,那么正如您所期望的那样,移动几乎是免费的。这是if动作operator=:
if (!__str._M_is_local()
&& (_Alloc_traits::_S_propagate_on_move_assign()
|| _Alloc_traits::_S_always_equal()))
// cheap move
else assign(__str);
Run Code Online (Sandbox Code Playgroud)
如果条件为真(_M_is_local()表示小字符串,此处描述),则移动很便宜。
如果为 false,则称为正常 assign(而不是移动)。当出现以下任一情况时就会出现这种情况:
assign会做一个简单的 memcpy (便宜)这是什么意思?
这意味着,如果您使用默认分配器(或具有前面提到的特征的任何分配器),那么移动仍然几乎是免费的。
另一方面,生成的代码不必要地庞大,我认为可以改进。它应该有一个单独的代码来处理常用的分配器,或者有一个更好的assign代码(问题是assign不检查_M_is_local(),但它会进行容量检查,因此编译器无法决定是否需要分配,所以它把不必要地将分配代码路径分配到可执行文件中 - 您可以在源代码中查看确切的详细信息)。