Ответ 1
Это исправлено в С++ 17. Ваш пример
std::vector<A> vec;
A &element = vec.emplace_back();
element.prop = "value";
является допустимым кодом С++ 17.
При использовании std::vector
s, std::list
(или других STL-контейнеров) я часто пишу это, для краткости кода (а не для ввода явного vec[index]
каждый раз) и эффективности распределения памяти (избегая копирования/переместить), и я полагаю, что я не единственный, кто может это сделать:
std::vector<A> vec;
vec.emplace_back();
A &element = vec[vec.size()-1];
element.prop = "value";
Почему методы STL-контейнеров emplace
, emplace_back
и emplace_front
не возвращают T&
?. Это позволит просто написать это, а не использовать теневой vec.size()-1
:
std::vector<A> vec;
A &element = vec.emplace_back();
element.prop = "value";
Это исправлено в С++ 17. Ваш пример
std::vector<A> vec;
A &element = vec.emplace_back();
element.prop = "value";
является допустимым кодом С++ 17.
У вас есть методы доступа к этим объектам, так как вы знаете, где они были вставлены. А именно front()
и back()
.
Некоторые другие функции (например, map::insert
) вернут итератор, потому что вы не знаете, как получить доступ к вставленному элементу в постоянное время. В случае emplace
вы знаете.
Еще одна причина не возвращать что-либо может быть производительность (большую часть времени вы не будете использовать возвращаемое значение). И в С++ вы платите за то, что используете.
Два аргумента для выбора этой сигнатуры:
Симметрия API. Эти API-интерфейсы симметричны с pop_back, pop_front и push и pop, как реализовано для очередей. Эти функции (поп-функции) имеют ситуацию, когда элемент может быть потерян при наличии исключения (т.е. Элемент удаляется из коллекции, но до того, как он будет возвращен, возникает исключение (например, если конструктор объекта может выбросить).
Используя эту функциональность (элемент чтения и поп-элемент) как две отдельные функции, обе могут быть реализованы транзакционно.
SRP. Это хорошее руководство по дизайну, что, если вы описываете поведение функции и вам нужно использовать слово "и", вы нарушили SRP и, вероятно, должны разбить его на две части (т.е. функция A, которая "добавляет элемент в конце и возвращает ссылку на него", вероятно, должно быть записано как две функции:" добавить элемент в конце "и" вернуть элемент в конце "- обе из которых могут предлагать по меньшей мере слабые исключения для клиентского кода).
Я не уверен, были ли эти критерии применены для дизайна, но я помню аргумент гарантии исключения, приведенный в лекции по безопасности исключений.
Вам это не нужно. Напишите это:
template<class C, class...Args>
auto emplace_back(C& c, Args&&...args)->decltype(c.back()){
c.emplace_back(std::forward<Args>(args)...);
return c.back();
}
и у вас есть семантика, которую вы хотите, без изменения интерфейса контейнера.
Просто:
emplace_back(vec).prop = "foo";