std :: vector的resize方法背后的设计原理是什么?

时间:2013-05-15 16:02:34

标签: c++ stdvector

模板类vector中的许多方法都对value_type个对象进行const引用,例如:

void push_back (const value_type& val);

resizevalue_type参数取值:

void resize (size_type n, value_type val = value_type());

作为一个非专业的C ++程序员,我只能想到这个选择的缺点(例如,如果size_of(value_type)足够大,可能会发生堆栈溢出)。因此,我想对那些对语言有更多见解的人提出这样的要求:

此选择背后的设计理由是什么?

2 个答案:

答案 0 :(得分:9)

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

此功能已从C ++ 11 删除

C ++ 11有resize() void resize( size_type count ); void resize( size_type count, const value_type& value);

value_type

这很容易理解。第一个使用{{1}}类型的默认构造对象在调整大小时填充向量,第二个使用在调整大小时从中复制的值。

答案 1 :(得分:6)

这似乎是一个设计缺陷,现在已经修复了。

引自STL defects 679

  

C ++ 98标准指定容器中的一个成员函数通过值而不是const引用传递其参数(T):

     

void resize(size_type sz,T c = T());

     

这一事实多年来一直在讨论/辩论,这是第一次在批准C ++ 98之前。按值传递此参数的基本原理是:

     

这样可以保证自引用语句有效,例如:

 v.resize(v.size() + 1, v[0]);  
     

然而,这个理由并不令人信服,因为push_back的签名是:

 void push_back(const T& x);
     

push_back具有类似的语义来调整大小(追加)。并且push_back也必须在自引用案例中起作用:

 v.push_back(v[0]);  // must work
     

通过值传递T的问题在于它比通过引用传递要贵得多。反过来也是如此,但是当它成立时它通常远不那么戏剧性(例如对于标量类型)。

     

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

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有效,那么我们也应该有效调整大小。采用参考参数的resize已经编码并在CodeWarrior库中发布,没有我所知道的问题报告。

     

提议的决议:

     

更改23.3.3 [deque],p2:

class deque {
   ...
   void resize(size_type sz, const T& c);
     

更改23.3.3.3 [deque.capacity],p3:

void resize(size_type sz, const T& c);  
     

更改23.3.5 [list],p2:

class list {
   ...
   void resize(size_type sz, const T& c);
     

更改23.3.5.3 [list.capacity],第3页:

 void resize(size_type sz, const T& c);
     

更改23.3.6 [vector],p2:

class vector {
   ...
   void resize(size_type sz, const T& c);
     

更改23.3.6.3 [vector.capacity],第11页:

void resize(size_type sz, const T& c);