【发布时间】:2018-10-08 06:18:11
【问题描述】:
libstdc++ 和 libc++ 都使 move-from std::string 对象为空,即使原始存储的字符串很短并且应用了短字符串优化。在我看来,这种清空会产生额外且不必要的运行时开销。例如,这里是来自 libstdc++ 的 std::basic_string 的移动构造函数:
basic_string(basic_string&& __str) noexcept
: _M_dataplus(_M_local_data(), std::move(__str._M_get_allocator())) {
if (__str._M_is_local())
traits_type::copy(_M_local_buf, __str._M_local_buf, _S_local_capacity + 1);
else {
_M_data(__str._M_data());
_M_capacity(__str._M_allocated_capacity);
}
_M_length(__str.length());
__str._M_data(__str._M_local_data()); // (1)
__str._M_set_length(0); // (2)
}
(1) 是一个在短字符串情况下无用的赋值,因为 data 已经设置为 local data,所以我们只是分配一个指针,它与之前分配的值相同。
(2) 清空字符串设置字符串大小并重置本地缓冲区中的第一个字符,据我所知,标准没有要求。
通常,库实现者会尝试尽可能高效地实现标准(例如,已删除的内存区域不会清零)。 我的问题是,是否有任何特殊原因导致移出的字符串被清空,即使它不是必需的,并且会增加不必要的开销。其中,可以很容易地消除,例如,通过:
basic_string(basic_string&& __str) noexcept
: _M_dataplus(_M_local_data(), std::move(__str._M_get_allocator())) {
if (__str._M_is_local()) {
traits_type::copy(_M_local_buf, __str._M_local_buf, _S_local_capacity + 1);
_M_length(__str.length());
}
else {
_M_data(__str._M_data());
_M_capacity(__str._M_allocated_capacity);
_M_length(__str.length());
__str._M_data(__str._M_local_data()); // (1)
__str._M_set_length(0); // (2)
}
}
【问题讨论】:
-
这也许是对遗留代码的致敬。在 SSO 进入 libstdc++ 之前,
std::string已被引用计数,并且所有移出字符串为空。旧代码可能(错误地)依赖它。 -
顺便说一句,在您建议的替换中,在使用它来设置目标长度之前,您不能将源长度设置为零。
-
@j6t 已更新,感谢您指出这一点。
-
与
operator=相同。
标签: c++ string move-semantics libstdc++