41

std::vector::resize从 pre-C++11发生变化背后的原因是什么:

void resize( size_type count, T value = T() );

到兼容的 C++11 形式:

void resize( size_type count );
void resize( size_type count, const value_type& value);
4

2 回答 2

47

C++11 标准的附件 C(兼容性)第 C.2.12 段规定:

更改:签名更改:resize

基本原理性能,与移动语义的兼容性

对原始功能的影响:对于传递给 resize 的vectordequelist填充值现在通过引用而不是按值传递,并且添加了额外的 resize 重载。使用此函数的有效 C++ 2003 代码可能无法使用此国际标准进行编译。

resize()功能是从value. resize()当向量的元素是默认可构造但不可复制(您可能希望稍后移动分配它们)时,这使得它无法使用。这解释了“与移动语义的兼容性”的基本原理。

此外,如果您不希望发生任何复制,它可能会很慢,而只是默认构造新元素。此外,value在 C++03 版本中,参数是按值传递的,这会产生不必要的副本的开销(正如 TemplateRex 在他的回答中提到的那样)。这解释了“性能”的基本原理。

于 2013-06-08T18:48:57.173 回答
17

一个原因是默认参数总是被传递,即在这种情况下被复制。正在做

 my_vector.resize(1000000) 

将复制 100 万个T对象。

std::allocator_traits<Alloc>::construct()在 C++11 中,您现在可以选择使用该函数复制用户提供的值或就地默认插入(即构造)元素。这允许vector使用 CopyInsertable 但不可 Copyable 的元素调整大小。

请注意,此更改已针对所有具有resize()成员(vector、和)的序列容器进行deque,但不适用于开头没有默认值参数的序列容器。forward_listliststd::string

更新:除了@AndyProwl 引用的当前标准的附件外,@HowardHinnant 的原始缺陷报告还澄清了:

通过值传递 T 的问题在于它可能比通过引用传递更昂贵。反之亦然,但是当它为真时,它通常远没有那么引人注目(例如,对于标量类型)。

即使移动语义可用,按值传递此参数也可能很昂贵。考虑例如向量>:

std::vector<int> x(1000); std::vector<std::vector<int>> v; ...
v.resize(v.size()+1, x); 

在按值传递的情况下,x 被复制一次到 resize 的参数中。然后在内部,由于代码在编译时无法通过调整大小来知道向量增长了多少,因此 x 通常会第二次从调整大小的参数复制(不移动)到向量中的适当位置。

使用 pass-by-const-reference,上例中的 x 只需复制一次。在这种情况下,x 有一个昂贵的副本构造函数,因此任何可以保存的副本都代表了显着的节省。

如果我们可以高效地 push_back,那么我们也应该高效地调整大小。采用参考参数的调整大小已在 CodeWarrior 库中编码和发布,没有我知道的问题报告。

于 2013-06-08T18:47:27.420 回答