【问题标题】:Why doesn't gcc use memmove in std::uninitialized_copy?为什么 gcc 不在 std::uninitialized_copy 中使用 memmove?
【发布时间】:2015-11-02 16:42:33
【问题描述】:

std::uninitialized_copy 复制到未初始化的内存范围。 这可以使用 memmove 按位可复制类型来完成。 我在 gdb 中逐步完成了下面的示例代码(使用 gcc 5.2.0 编译)。 因此我观察到memmove 根本没有被使用。

在示例中__is_trivial(Bar) 用于确定是否可以使用memmove。 它(正确地)计算为false,因为Bar 有一个重要的默认构造函数(参见bits/stl_uninitialized.h123ff 中对std::__uninitialized_copy<false>::__uninit_copy(...) 的调用)。 但是为什么__is_trivial 甚至与std::uninitialized_copy 相关? 根据Bjarne std::is_trivially_copyable 应该足够了。请注意,后者在示例中计算为true,即。 memmove优化is applicable

我知道,该标准不需要std::uninitialized_copy 的任何特定实现。我只是想知道为什么 __is_trivial 受到青睐,即使 std::is_trivially_copyable 作为 gcc 实现的适用替代方案存在?

示例代码:

#include <iostream>
#include <memory>
#include <vector>
#include <type_traits>

struct Bar
{
   Bar () : v(42) {};
   Bar(Bar const &) = default;
   Bar(Bar &&) = default;
   Bar & operator=(Bar &&) = default;
   Bar & operator=(Bar const &) = default;
   ~Bar() = default;
   int v;
};

int main() {
   std::cout
      << std::is_trivially_move_constructible<Bar>::value
      << " " << std::is_trivially_copy_constructible<Bar>::value
      << " " << std::is_trivially_copyable<Bar>::value
      << " " << std::is_trivial<Bar>::value
      << " " << __is_trivial(Bar) << std::endl;
   size_t const num_elements = 1 << 27;
   std::vector<Bar> v(num_elements);
   Bar * vc = (Bar *) std::malloc(num_elements * sizeof(Bar));
   std::uninitialized_copy(v.begin(), v.end(), vc);
   std::free(vc);
}

示例输出:1 1 1 0 0

更新:我们做了一些测试,比较了memmoveuninitialized_copy 和一个简单的for 循环的实际运行时间。如果Bar 微不足道(参见__is_trivial(Bar)),uninitialized_copymemmove 一样快,否则,uninitialized_copy 与我们的for 循环一样快。总体而言,memmove 仅在较小的Bars 上明显更快(2x)(即将int v; 更改为char v;)。否则性能基本相同。

编辑:更正对std::is_trivially_... 的引用。更准确地说明标题。

【问题讨论】:

  • 您混淆了is_trivially_copy_constructibleis_trivially_copyable。 Bjarne 的示例代码使用的是第二个,而不是第一个。
  • 没错,我已经更正了这个问题。问题仍然存在,因为 is_trivially_copyable 也评估为 true
  • 您复制到未初始化的内存范围。我解释它的方式,不能有重叠(因为一个被初始化另一个没有),所以你可以使用memcpy而不是memmove
  • libstdc++ 欢迎补丁(如果你不想花时间的话,也可以加入 bugzilla 条目)。
  • 请注意,GCC 在 GCC 5 之前没有 __is_trivially_copyable 内在函数。

标签: c++ c++11 gcc stl


【解决方案1】:

对于未来的读者:这已作为 gcc 增强 here 提交。

【讨论】:

    猜你喜欢
    • 2021-05-07
    • 1970-01-01
    • 2016-09-07
    • 2020-12-03
    • 2019-08-07
    • 2015-08-17
    • 2016-09-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多