【问题标题】:Examples where std::vector::emplace_back is slower than std::vector::push_back?std::vector::emplace_back 比 std::vector::push_back 慢的示例?
【发布时间】:2015-10-05 05:14:02
【问题描述】:

我目前正在阅读 Scott Meyer 的“Effective Modern C++”。在第 42 项中,他声称,例如std::vector::emplace_back 通常(但并非总是)与使用 push_back 一样快,甚至更快。他列出了三个条件至少应该一样快,但在这些条件不完全满足的情况下没有提供反例。 有人可以给我举个例子,使用emplace_back 会导致性能比使用push_back 更差吗?

【问题讨论】:

  • 这不是一回事,但你不能将emplace_back 用于大括号初始化程序(例如,调用像vecOfVecs.emplace_back({1, 2, 3}); 这样的列表构造函数),所以我想这不会像快到push_back
  • He lists three conditions 是?
  • 如果emplace_back 实际上是更慢,那将是一个非常模糊和奇怪的情况。它通常相同或更好。
  • Scott Meyers 在 @Meeting C++ 2014 here 的主题演讲中提到了这个确切的问题。享受吧。

标签: c++ performance vector


【解决方案1】:

这取决于您所说的“emplace_backpush_back 慢”的意思。考虑构建成本高且复制成本低的类,例如具有写入时复制行为的类,或表示哈希值的类:

class Hash {
    public:
    int value;
    Hash(const char *data) : value(very_expensive_hash_function(data)) {} // expensive
    Hash(const Hash &other) : value(other.value) {} // cheap
};
Hash h(foo);
std::vector<Hash> v;

v.push_back(h);        // 1
v.emplace_back("foo"); // 2

那么,(1) 确实会比 (2) 快。然而,这样的比较是不公平的。在比较性能时,应考虑所涉及的构造函数的成本。

【讨论】:

    【解决方案2】:

    愚蠢的例子:

    std::vector<always_throws_on_construction> vec;
    if(vec.size() == vec.capacity())
    {
        vec.push_back(always_throws_on_construction());
    }
    

    可能会比

    更快
    std::vector<always_throws_on_construction> vec;
    if(vec.size() == vec.capacity())
    {
        vec.emplace_back();
    }
    

    【讨论】:

    • 猜测的理由是什么?
    • @black 在推回的情况下,您在运行任何向量代码之前抛出异常。在 emplace 后部案例中,您动态扩展向量以能够处理新元素然后抛出。就像我说的,这是一个愚蠢的例子。 [编辑清楚抛出异常]
    • 哦,是的。出于某种原因,我认为你说的相反,这就是我问的原因。
    【解决方案3】:

    基本上这归结为标准实现。从理论上讲,emplace 应该总是一样快或更快,但现实情况是没有标准库实现充分利用这一点。

    几年前他就这个问题发表过演讲:https://www.youtube.com/watch?t=3427&v=smqT9Io_bKo

    查看演讲的前 1 小时,了解更详细的说明。谈话结束时的问答也很重要。

    【讨论】:

      猜你喜欢
      • 2015-01-15
      • 2017-09-21
      • 2019-05-22
      • 2017-01-12
      • 1970-01-01
      • 2021-06-02
      • 1970-01-01
      • 1970-01-01
      • 2012-02-05
      相关资源
      最近更新 更多