std::vector::emplace_back 比 std::vector::push_back 慢的示例?

Posted

技术标签:

【中文标题】std::vector::emplace_back 比 std::vector::push_back 慢的示例?【英文标题】:Examples where std::vector::emplace_back is slower than 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 的主题演讲中提到了这个确切的问题。享受吧。 【参考方案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 小时,了解更详细的说明。谈话结束时的问答也很重要。

【讨论】:

以上是关于std::vector::emplace_back 比 std::vector::push_back 慢的示例?的主要内容,如果未能解决你的问题,请参考以下文章

std::emplace_back 调用向量中其他对象的构造函数?