【问题标题】:Should I replace all calls to push_back with emplace_back?我应该用 emplace_back 替换所有对 push_back 的调用吗?
【发布时间】:2014-03-18 01:37:54
【问题描述】:

在我的 C++ 应用程序中,我大量使用像 vector 这样的 STL 容器。 push_back的电话很多,一直担心不必要的构造和复制操作。

我的应用程序非常低级,我非常关心 CPU 和内存使用情况。我应该将所有对push_back 的调用替换为对emplace_back 的调用吗?

我正在使用 Visual Studio 2013。

【问题讨论】:

标签: c++ visual-studio c++11 stl


【解决方案1】:

我将所有对push_back 的调用替换为对emplace_back 的调用,并注意到以下情况:

  • RAM 使用量减少了大约 20%(更新:这可能是由于其他影响)
  • CPU 使用率不变
  • 二进制文件略小 (x64)
  • 没有兼容性问题

根据这些经验,如果您的项目不需要向后兼容旧的编译器,我强烈建议您从 push_back 迁移到 emplace_back

【讨论】:

  • 如何判断替换函数会减少 RAM?
  • @Billz,当您的程序使用 push_back 时,您测量 RAM 使用情况,然后将其替换为 emplace_back 并再次测量。
  • @billz:正如 Rob 在之前和之后写的那样,我就是这么做的。这得益于我的应用程序是一个用户体验监控产品 (helgeklein.com/uberagent-for-splunk)。
【解决方案2】:

这几乎是一条规则。您不能依赖复制构造函数的副作用,因此这应该意味着明确地跳过它是正确的做法,但有一种情况。

std::vector<std::unique_ptr<A>> foo;
foo.emplace_back( new A );

如果在某个时间触发了 throw,例如当向量调整大小时,您会以泄漏结束。所以 emplace_back 是不可能的。

如果A 构造函数和您发送的参数是异常安全的,那么没有理由不使用emplace_back。

【讨论】:

  • 虽然在这种情况下,您应该编写自己的make_unique 函数,将参数转发给std::unique_ptr 构造函数,这样就不用担心这个问题了。在 Visual Studio 中,您必须手动消除一些采用不同数量参数的重载,这很痛苦,但值得提高安全性。
【解决方案3】:

本次测试:

#include <type_traits>
#include <typeinfo>
#include <iostream>
#ifndef _MSC_VER
#   include <cxxabi.h>
#endif
#include <memory>
#include <string>
#include <cstdlib>
#include <vector>

template <typename T>
std::string
type_name()
{
    typedef typename std::remove_reference<T>::type TR;
    std::unique_ptr<char, void(*)(void*)> own
           (
#ifndef _MSC_VER
                abi::__cxa_demangle(typeid(TR).name(), nullptr,
                                           nullptr, nullptr),
#else
                nullptr,
#endif
                std::free
           );
    std::string r = own != nullptr ? own.get() : typeid(TR).name();
    if (std::is_const<TR>::value)
        r += " const";
    if (std::is_volatile<TR>::value)
        r += " volatile";
    if (std::is_lvalue_reference<T>::value)
        r += "&";
    else if (std::is_rvalue_reference<T>::value)
        r += "&&";
    return r;
}

template <int N>
struct member
{
    member()
    {
        std::cout << type_name<member>() << "()\n";
    }

    ~member()
    {
        std::cout << "~" << type_name<member>() << "()\n";
    }

    member(member const& x)
    {
        std::cout << type_name<member>()
                  << "(" << type_name<decltype(x)>() << ")\n";
    }

    member& operator=(member const& x)
    {
        std::cout << type_name<member>() << "::operator=("
                  << type_name<decltype(x)>() << ")\n";
        return *this;
    }

    member(member&& x)
    {
        std::cout << type_name<member>()
                  << "(" << type_name<decltype(x)>() << ")\n";
    }

    member& operator=(member&& x)
    {
        std::cout << type_name<member>() << "::operator=("
                  << type_name<decltype(x)>() << ")\n";
        return *this;
    }
};

int
main()
{
    std::vector<member<1>> v;
    v.reserve(10);
    member<1> m;
    std::cout << "\npush_back an lvalue\n";
    v.push_back(m);
    std::cout << "\nemplace_back an lvalue\n";
    v.emplace_back(m);
    std::cout << "\npush_back an xvalue\n";
    v.push_back(std::move(m));
    std::cout << "\nemplace_back an xvalue\n";
    v.emplace_back(std::move(m));
    std::cout << "\npush_back a prvalue\n";
    v.push_back(member<1>{});
    std::cout << "\nemplace_back an prvalue\n";
    v.emplace_back(member<1>{});
    std::cout << "\nDone\n";
}

对我来说输出:

member<1>()

push_back an lvalue
member<1>(member<1> const&)

emplace_back an lvalue
member<1>(member<1> const&)

push_back an xvalue
member<1>(member<1>&&)

emplace_back an xvalue
member<1>(member<1>&&)

push_back a prvalue
member<1>()
member<1>(member<1>&&)
~member<1>()

emplace_back an prvalue
member<1>()
member<1>(member<1>&&)
~member<1>()

Done
~member<1>()
~member<1>()
~member<1>()
~member<1>()
~member<1>()
~member<1>()
~member<1>()

即我不希望有任何不同。

【讨论】:

    猜你喜欢
    • 2011-10-26
    • 1970-01-01
    • 2011-05-17
    • 1970-01-01
    • 2015-05-19
    • 2021-10-12
    • 2014-03-31
    • 2012-06-09
    相关资源
    最近更新 更多