为什么没有emplace/_front/_back返回引用?

Ele*_*ntW 21 c++ stl return-value c++11

当使用std::vectors,std::lists(或其他STL容器)时,我碰巧经常写这个,因为代码短缺(而不是vec[index]每次都显式)和内存分配效率(避免复制/移动),我想我不是只有一个这样做:

std::vector<A> vec;
vec.emplace_back();
A &element = vec[vec.size()-1];
element.prop = "value";
Run Code Online (Sandbox Code Playgroud)

为什么不STL容器emplace,emplace_backemplace_front方法返回一个T&这将允许一个人简单地写这个而不是使用阴影vec.size()-1:

std::vector<A> vec;
A &element = vec.emplace_back();
element.prop = "value";
Run Code Online (Sandbox Code Playgroud)

Joh*_*åde 21

这已在C++ 17中修复.你的榜样

std::vector<A> vec;
A &element = vec.emplace_back();
element.prop = "value";
Run Code Online (Sandbox Code Playgroud)

是有效的C++ 17代码.

  • 为什么是引用而不是迭代器? (3认同)

qua*_*dev 11

您有成员方法来访问这些对象,因为您知道它们的插入位置.即front()back().

一些其他函数(例如map::insert)将返回迭代器,因为您不知道如何在恒定时间内访问插入的元素.在这种情况下emplace,你知道.

不返回任何内容的另一个原因可能是性能(大多数情况下您不会使用返回的值).在C++中,您需要为使用的内容付费.

  • 编译器优化不使用返回值的 `emplace_back` 的可能性很高(因为大部分函数被内联的可能性很高,编译器可以简单地删除与返回相关的死代码)。另一方面,编译器优化 `emplace_back()` 后跟 `back()` 的可能性非常低,因为它需要跨两个不同的函数进行优化并“查看”动态分配给存储和能够跟踪“size”成员的值并查看是否访问了刚刚插入的元素。 (2认同)

utn*_*tim 8

选择此签名的两个参数:

  • API对称性.这些API与pop_back,pop_front以及为队列实现的push和pop对称.这些函数(pop函数)有一种情况,即元素在异常存在时可能会丢失(即元素从集合中删除,但在返回之前发生异常(例如,如果对象的构造函数可以抛出).

    通过将此功能(读取元素和pop元素)实现为两个单独的函数,两者都可以以事务方式实现.

  • SRP.这是一个很好的设计指导,如果你描述一个函数的行为,并需要使用"和"字,你已经打破SRP和它应该有两种可能分裂(即A功能"的结尾追加一个元素返回对它的引用"应该写成两个函数"在末尾添加一个元素"和"在末尾添加返回元素" - 这两个函数都可以为客户端代码提供至少弱异常保证.

我不确定这些标准是否适用于设计,但我记得在关于异常安全的讲座中给出的异常保证参数.


Yak*_*ont 8

你不需要它.写这个:

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();
}
Run Code Online (Sandbox Code Playgroud)

并且您拥有所需的语义,而无需修改容器界面.

只是:

emplace_back(vec).prop = "foo";
Run Code Online (Sandbox Code Playgroud)