为什么在C ++ 11中更改了std :: vector :: resize签名?

时间:2013-06-08 18:44:12

标签: c++ c++11 vector stl resize

从{C ++ 11之前的std::vector::resize更改背后的原因是什么:

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

到兼容的C ++ 11表单:

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

2 个答案:

答案 0 :(得分:47)

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

  

更改:签名更改:resize

     

理由性能,与移动语义的兼容性

     

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

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

此外,如果您不希望发生任何副本,只需要默认构造的新元素,它可能会很慢。此外,value参数在C ++ 03版本中按值传递,这会导致不必要的副本(as mentioned by TemplateRex in his answer)的开销。这解释了“性能”的基本原理。

答案 1 :(得分:17)

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

 my_vector.resize(1000000) 

将复制100万个T个对象。

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

请注意,已对包含resize()成员(vectordequeforward_listlist)的所有序列容器进行了此更改,但不是对于std::string,它没有默认值参数。

更新:除了@AndyProwl引用的当前标准的附件外,@ HowardHinnant的original defect report也澄清了:

  

传递T值的问题在于它可能是显着的   比通过参考更昂贵。反过来也是如此,   然而,如果它是真的,它通常远不那么引人注目(例如   标量类型)。

     

即使有可用的移动语义,也可以按值传递此参数   可能很贵。考虑例如vector&gt;:

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

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

     

使用pass-by-const-reference,上面例子中的x需要   只复制一次。在这种情况下,x具有昂贵的复制构造函数   因此,任何可以保存的副本都可以节省很多。

     

如果我们能够有效地使用push_back,那么我们应该有效率   调整大小。采用参考参数的调整大小已被编码   并在CodeWarrior库中提供,没有任何问题报告   我知道的。