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

What is the design rationale behind the resize method of std::vector?

本文关键字:是什么 resize 方法 背后 vector      更新时间:2023-10-16

模板类vector中的许多方法接受value_type对象的const引用,例如:

void push_back (const value_type& val);

resize取其value_type参数值:

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

作为一个非专业的c++程序员,我只能想到这种选择的缺点(例如,如果size_of(value_type)足够大,可能会发生堆栈溢出)。我想对更了解这门语言的人提出的问题是:

这个选择背后的设计原理是什么?

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类型的默认构造对象来填充向量,第二个在调整大小时获取一个值来复制。

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

引用STL缺陷679

c++ 98标准规定,容器中只有一个成员函数按值传递其形参(T),而不是通过const引用:

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

这个事实多年来一直被反复讨论/争论,第一次甚至是在c++ 98被批准之前。按值传递该参数的基本原理是:

使自引用语句保证工作,例如:

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

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

 void push_back(const T& x);

和push_back具有与resize (append)类似的语义。push_back也必须在自引用的情况下工作:

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

按值传递T的问题是,它可能比按引用传递要昂贵得多。反之也成立,但是当它成立时,通常不那么引人注目(例如对于标量类型)。

即使有move语义可用,按值传递该参数的代价也会很高。例如,考虑vector>:

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

在按值传递的情况下,x被复制一次到参数resize。然后在内部,由于代码在编译时无法知道resize使vector增长了多少,因此通常将x从resize的形参第二次复制(而不是移动)到vector中的适当位置。

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

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

提出解决方法:

Change 23.3.3 [deque], p2:

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

更改23.3.3.3 [deque。]能力,p3:

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

Change 23.3.5 [list], p2:

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

更改23.3.5.3 [list.]能力,p3:

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

Change 23.3.6 [vector], p2:

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

更改23.3.6.3[向量]。能力,赛:

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