Подтвердить что ты не робот

Почему нельзя было перегружать push_back для выполнения задания emplace_back?

Во-первых, я знаю этот вопрос, но я не верю, что я прошу то же самое.

Я знаю, что делает std::vector<T>::emplace_back, и я понимаю, почему я буду использовать его поверх push_back(). Он использует вариационные шаблоны, позволяющие мне пересылать несколько аргументов конструктору нового элемента.

Но я не понимаю, почему комитет по стандарту С++ решил, что существует потребность в новой функции-члене. Почему они не могут просто расширить функциональность push_back(). Насколько я вижу, push_back может быть перегружен в С++ 11:

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

Это не нарушит совместимость в обратном направлении, позволяя вам передавать N аргументов, включая аргументы, которые будут вызывать обычный конструктор rvalue или copy. Фактически реализация GCC С++ 11 push_back() просто вызывает emplace_back:

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

Итак, как я его вижу, нет необходимости в emplace_back(). Все, что им нужно было добавить, это перегрузка для push_back(), которая принимает вариационные аргументы и пересылает аргументы конструктору элемента.

Я здесь не прав? Есть ли какая-то причина, что здесь нужна совершенно новая функция?

4b9b3361

Ответ 1

Если T имеет явный конструктор преобразования, между emplace_back и push_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 будет законным в этом случае, и я полагаю, что это нежелательное поведение. Я не знаю, является ли это причиной, но это единственное, что я могу придумать.

Ответ 2

Вот еще один пример.

Честно говоря, эти два семантически отличаются друг от друга, что их сходное поведение следует рассматривать как простое совпадение (из-за того, что С++ имеет "конструкторы копирования" с определенным синтаксисом).

Вы действительно не должны использовать emplace_back, если вы не хотите использовать семантику на месте.
Редко, что вам нужно такое. Обычно 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 &)
}