为啥 std::vector 需要 is_trivial 进行按位移动,而不仅仅是 is_trivially_copyable?
Posted
技术标签:
【中文标题】为啥 std::vector 需要 is_trivial 进行按位移动,而不仅仅是 is_trivially_copyable?【英文标题】:Why does std::vector require is_trivial for bitwise move, rather than just is_trivially_copyable?为什么 std::vector 需要 is_trivial 进行按位移动,而不仅仅是 is_trivially_copyable? 【发布时间】:2020-01-10 22:56:44 【问题描述】:我在 libstdc++ stl_uninitialized.h 中看到了这段代码:
// This class may be specialized for specific types.
// Also known as is_trivially_relocatable.
template<typename _Tp, typename = void>
struct __is_bitwise_relocatable
: is_trivial<_Tp> ;
template <typename _Tp, typename _Up>
inline __enable_if_t<std::__is_bitwise_relocatable<_Tp>::value, _Tp*>
__relocate_a_1(_Tp* __first, _Tp* __last,
_Tp* __result, allocator<_Up>&) noexcept
ptrdiff_t __count = __last - __first;
if (__count > 0)
__builtin_memmove(__result, __first, __count * sizeof(_Tp));
return __result + __count;
但在我看来,memmove 对于可以简单复制的对象来说会很好,即使它们不是简单默认可构造的。在这种情况下,谁在乎默认构造函数?
【问题讨论】:
相关讨论:gcc.gnu.org/bugzilla/show_bug.cgi?id=87106 看来这个 bugzilla 线程是这个 __is_bitwise_relocatable 特征的起源(我没有关注太多讨论)。然后我的问题变成了:is_trivially_copyable 本身不足以启用 __is_bitwise_relocatable 并触发 memcpy 有什么原因吗? 对于那些感兴趣的人:folly::FBVector 允许您手动将一个类标记为可重定位,这样您就可以获得 memcpy 的性能优势。 说到 FBVector:我的 WG21 提案 P1144 "Object relocation in terms of move plus destroy"(针对 C++2b 或更高版本)在我的 Clang 分支中实现,在编译器资源管理器 here 上。 libstdc++、libc++ 和 MSVC 都乐于在没有构造函数调用的情况下弹出trivial
类型(例如,通过 memcpy
或 memmove
),并且都不愿意以相同的方式弹出 trivially_copyable
类型。这适用于 vector::reserve
和 uninitialized_copy
。
【参考方案1】:
我在 bugzilla 线程上询问了这个问题,他们将我指向 https://***.com/questions/47464819。本质上,memcpy 不足以启动对象的生命周期,除非默认构造函数也是微不足道的。因此,就内存中的位而言,它在技术上是可以的,但根据标准,它是未定义的行为。由于这个库代码是由编译器团队编写的,如果他们认为它是安全的,他们无论如何都有权这样做,但他们显然不相信安全性。
【讨论】:
一个很好的说法是(在标准级别)微不足道的可复制性适用于对象之间,而不是对象和内存之间。 “由于这个库代码是由编译器团队编写的,如果他们认为它是安全的,他们无论如何都有权这样做” ...是的,理论上,但是我知道事实上它不使用 GCC 是安全的。我们只允许在结果仍然正确的情况下打破这样的语义规则,但在这种情况下,无论它是否在库头中,都会触发未定义的行为。以上是关于为啥 std::vector 需要 is_trivial 进行按位移动,而不仅仅是 is_trivially_copyable?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 std::vector 需要 is_trivial 进行按位移动,而不仅仅是 is_trivially_copyable?
为啥从 std::vector 中随机删除比 std::list 快?
为啥 std::vector 没有 append 方法? [关闭]
为啥 std::vector::data() 中没有使用指针 typedef?