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

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); 

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

更改 :签名更改: resize

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

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

旧的resize()函数是从value复制构build新的元素。 当vector的元素是default-constructible但是不可复制的(你可能想稍后移动它们resize()时,这就不可能使用resize() )。 这解释了“ 与移动语义的兼容性 ”的基本原理。

而且,如果你不想要任何副本发生,可能会很慢,只是默认构build的新元素。 另外, value参数在C ++ 03版本中被传递,这会导致不必要的副本的开销( 如TemplateRex在他的回答中所提到的 )。 这解释了“ 性能 ”的基本原理。

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

  my_vector.resize(1000000) 

会复制100万个T对象。

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

请注意,对具有resize()成员( vectordequeforward_listlist )的所有序列容器都进行了此更改,但是对于没有缺省值参数的std::string ,此更改已经完成。

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

按价值传递T的问题在于,它可能比通过引用传递要贵得多。 反过来也是如此,但是当它是真实的时候,它通常远不那么戏剧化(例如对于标量types)。

即使移动语义可用,通过值传递这个参数可能是昂贵的。 考虑例如vector>:

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

在传值的情况下,x被复制一次到resize的参数。 然后在内部,由于代码无法在编译时知道resize的vector增长了多less,x通常会从resize的参数复制(不移动)到vector中的适当位置。

通过传递const引用,上面例子中的x只需要被复制一次。 在这种情况下,x有一个昂贵的复制构造函数,所以可以保存的任何副本都可以节省很多。

如果我们能够有效地使用push_back,那么我们也应该高效地resize。 采用引用参数的resize已被编码并在CodeWarrior库中提供,没有我知道的问题报告。