繁体   English   中英

位置 function 通过就地构造而不是通过分配向容器添加新元素是什么意思?

[英]What does it mean that the emplacement function adds a new element to a container via construction in place istead of via assignment?

Effective Modern C++的第 41 项中,Scott Meyers 提到了这种差异及其对插入效率的影响。

我对此有一些疑问,但在提出问题之前,我需要了解这两种添加元素的方式之间的区别是什么。

考虑书中的代码示例:

std::vector<std::string> vs;
// adding some elements to vs
vs.emplace(v.begin(), "xyzzy");

很明显,在// adding some elements to vs之后,可能是

  • vs.capacity() == vs.size() ,或
  • vs.capacity() > vs.size()

相应地,

  • vs必须重新分配,并且 vs 中的所有预先存在的元素(那些名为vs vs[0]vs[1] ,...在重新分配发生之前)必须移动构造到新的 memory 位置(新位置的vs[1] , vs[2] , ...)
  • vs必须vs.resize(vs.size() + 1)并且所有预先存在的元素必须移动分配给下一个索引,显然是向后处理,从最后一个元素到第一个元素。

(显然我提到了移动操作,因为std::string提供了noexcept移动操作。如果不是这种情况,那么上面的场景略有不同,将使用复制操作。)

然而,我的问题的症结所在,就在上面的代码之后,书上写着(我的斜体

[…] 很少有实现会将添加的std::string构造到由vs[0]占用的 memory中。 相反,他们会将值移动分配到位。 […]

在完成房间以容纳新元素之后,这两种情况是什么?

  • 如果emplace通过移动赋值添加元素,则意味着它确实v[0] = std::string{strarg}; 其中strarg == "xyzzy" ,对吗?
  • 但是构造v[0]占用的元素的另一种情况是什么? 这是一个new的展示位置吗? 它会是什么样子? 我想它应该类似于Placement new here部分的代码块,但我不确定在这种情况下它会是什么样子。

有许多不同的方式来实现emplace ,并且标准对于实现必须如何做到这一点非常松懈。

给定一个指向由std::allocator_traits<allocator_type>::allocate的位置的指针,向量构造新 object 的唯一方法是使用std::allocator_traits<allocator_type>::construct 对于默认分配器,这将调用placement new。

现在,如果确实发生了重新分配,放置新元素的明显方法是调用allocator_traits::construct(get_allocator(), ptr, std::forward<Args>(args...)) 这将等效于new (ptr) std::string("xyzzy") 但请注意,所有其他元素也通过allocator_traits::construct(get_allocator(), ptr, std::move(old_ptr))移动构造到新缓冲区。

如果没有发生重新分配,大多数实现只会使用value_type(std::forward<Args>(args...))构造一个元素并从中移动分配(相当于v[0] = std::string("xyzzy") )。 这就是 libstdc++ 所做的。

或者,代替移动构造v[0] = std::string("xyzzy") , object 可以通过allocator_traits::destroy(&v[0])->~value_type()用于默认分配器)销毁,然后可以通过allocator_traits::construct就地构造它。 这似乎更难实现,因为如果移动构造函数抛出,需要特别注意确保元素不会被破坏两次,这可能就是为什么只有“少数实现”会这样做。

顺便说一句,没有强大的异常保证,因此不一定要使用move_if_noexcept ,并且可以始终调用移动构造函数,即使移动构造函数不是noexcept

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM