【问题标题】:Why couldn't push_back be overloaded to do the job of emplace_back?为什么不能重载 push_back 来完成 emplace_back 的工作?
【发布时间】:2011-10-23 10:57:17
【问题描述】:

首先,我知道this question,但我不相信我在问同样的问题。

我知道 std::vector<T>::emplace_back 的作用 - 我明白为什么我会使用它而不是 push_back()。它使用可变参数模板,允许我将多个参数转发给新元素的构造函数。

但我不明白为什么 C++ 标准委员会决定需要一个新的成员函数。为什么他们不能简单地扩展push_back() 的功能。据我所知,push_back 可以在 C++11 中重载为:

template <class... Args>
void push_back(Args&&... args);

这不会破坏向后兼容性,同时允许您传递 N 个参数,包括会调用普通右值或复制构造函数的参数。事实上,push_back() 的 GCC C++11 实现只是简单地调用了 emplace_back:

  void push_back(value_type&& __x)
  { 
    emplace_back(std::move(__x)); 
  }

所以,在我看来,不需要emplace_back()。他们需要添加的只是push_back() 的重载,它接受可变参数,并将参数转发给元素构造函数。

我错了吗?这里需要一个全新的功能有什么原因吗?

【问题讨论】:

  • 好问题。 @moka 他知道这两个功能之间的区别。他甚至链接到那个特定的问题。
  • 它们有不同的含义,这一切都在你提到的你阅读的问题中得到了解释。比较 v.emplace_back(123)v.push_back(123) 例如 vector&lt;SomeType&gt; v;int 的隐式转换。
  • @Gene:好的,我已经对它们进行了比较,我看不出如果将 push_back 简单地修改为 emplace_back 所做的事情会有什么不同。你介意在这里解释一下吗?
  • 这是库开发的标准做法。你不改变你的界面,你创造一个新的。然后允许用户按照自己的进度按照新 API 实现旧 API,同时代码永不损坏。

标签: c++ c++11


【解决方案1】:

如果 T 具有显式转换构造函数,则 emplace_backpush_back 之间的行为不同。

struct X
{
    int val;
    X() :val() {}
    explicit X(int v) :val(v) {}
};

int main()
{
    std::vector<X> v;
    v.push_back(123);    // this fails
    v.emplace_back(123); // this is okay
}

进行您建议的更改将意味着 push_back 在这种情况下是合法的,我认为这不是理想的行为。我不知道是不是这个原因,但这是我唯一能想到的。

【讨论】:

  • 在处理unique_ptrs 的容器时特别有用,因为v.emplace_back(new foo)v.push_back(std::unique_ptr&lt;foo&gt;(new foo)) 简单得多。但在这种情况下,应该能够明确请求转换。
  • @AlexandreC.:实际上,emplace_back(new foo) 不是异常安全的,所以这是错误的做法。
  • @AlexandreC.:是的——特别是扩大向量所需的潜在分配。这里要吸取的一个潜在的元教训是:在实际上没有必要使用时,不要出于纯粹的懒惰而使用新功能。
  • @AlexandreC.: 不知道你是不是在开玩笑,但如果你不坚持原来的,你应该只使用push_back(make_unique&lt;foo&gt;())(这对我来说也可以).. .
  • @Mehrdad C++ 最近变得有点冗长,不是吗。是的,模板是个笑话。我完全同意你的看法,但在我写那条评论的时候,我们使用的是 Visual Studio 2010,不支持 make_unique,我们仍然偶尔会用它编译代码。如今,我们在代码库中使用 grep 搜索 newdelete
【解决方案2】:

这是另一个例子。

老实说,两者在语义上如此不同,它们的相似行为应该被视为仅仅是巧合(因为 C++ 具有“复制构造函数”特定的语法)。

你真的应该使用emplace_back,除非你想要in-place-construction语义。
你很少需要这样的东西。一般来说,push_back 是你真正想要的。

#include <vector>

struct X { X(struct Y const &); };
struct Y { Y(int const &); operator X(); };

int main()
{
    std::vector<X> v;
    v.   push_back(Y(123));  // Calls Y::operator X() and Y::Y(int const &)
    v.emplace_back(Y(123));  // Calls X::X(Y const &) and Y::Y(int const &)
}

【讨论】:

    猜你喜欢
    • 2014-07-06
    • 2012-06-09
    • 2011-05-17
    • 2020-05-26
    • 2023-02-02
    • 2013-08-18
    • 2022-07-06
    • 2021-10-12
    相关资源
    最近更新 更多