为啥 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 类型(例如,通过 memcpymemmove),并且都不愿意以相同的方式弹出 trivially_copyable 类型。这适用于 vector::reserveuninitialized_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?

为啥使用 std::vector 而不是 realloc? [关闭]

为啥 std::vector<bool> 没有 .data()?