为什么std::vector::resize签名在c++ 11中被改变了?

Why has the std::vector::resize signature been changed in C++11?

本文关键字:c++ 改变 vector std resize 为什么      更新时间:2023-10-16

std::vector::resize与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);

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

Change: Signature changes: resize

基本原理: 性能,与move语义的兼容性.

对原始特征的影响:对于vector, dequelist,传递给调整大小的填充值现在被传递引用而不是按值,并且增加了resize的额外重载。有效的c++ 2003代码使用此功能的程序可能无法与本国际标准进行编译。

旧的resize()函数是从value复制构造新元素。这使得当vector的元素是默认可构造但不可复制时(您可能希望稍后对它们进行移动赋值),不可能使用resize()。这解释了"与move语义兼容"的基本原理。

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

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

 my_vector.resize(1000000) 

将复制100万个T对象。

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

请注意,此更改已对所有具有resize()成员(vector, deque, forward_listlist)的序列容器执行,但不包括没有默认值参数的std::string

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

按值传递T的问题是它可能是显著的比通过引用传递更昂贵。反之亦然,然而,当它是真的时,它通常远没有那么戏剧性(例如for标量类型)。

即使move语义可用,也要按值传递该参数可能会很贵。例如,考虑vector>:

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

在按值传递的情况下,x被复制一次到resize参数。然后在内部,因为代码可以在编译时不知道向量x的大小调整了多少通常从resize的参数中复制(而不是移动)第二次

通过const-reference传递,上面例子中的x需要只复制一次。在这种情况下,x有一个昂贵的复制构造函数因此,任何可以保存的副本都代表着显著的节省。

如果我们可以有效地处理push_back,那么我们也应该有效地处理调整大小。采用引用参数的调整大小已被编码并在CodeWarrior库中发布,没有任何问题报告