为什么在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的影响 :对于
vector
,deque
和list
,传递给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()
成员( vector
, deque
, forward_list
和list
)的所有序列容器都进行了此更改,但是对于没有缺省值参数的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库中提供,没有我知道的问题报告。