为啥在 C++11 中更改了 std::vector::resize 签名?
Posted
技术标签:
【中文标题】为啥在 C++11 中更改了 std::vector::resize 签名?【英文标题】:Why has the std::vector::resize signature been changed in C++11?为什么在 C++11 中更改了 std::vector::resize 签名? 【发布时间】:2013-06-04 20:35:27 【问题描述】: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);
【问题讨论】:
【参考方案1】:C++11 标准附录 C(兼容性)的 C.2.12 段规定:
更改:签名更改:
resize
基本原理:性能、与移动语义的兼容性。
对原始特征的影响:对于
vector
、deque
和list
,传递给 resize 的填充值现在通过 引用而不是按值,并且添加了额外的调整大小重载。有效的 C++ 2003 代码 使用此功能的可能无法按照本国际标准编译。
旧的resize()
函数是从value
复制构造新元素。当向量的元素是默认可构造但不可复制(您可能希望稍后移动分配它们)时,这使得无法使用resize()
。这解释了“与移动语义的兼容性”的基本原理。
此外,如果您不希望出现任何副本,则可能会很慢,只希望默认构造新元素。此外,value
参数在 C++03 版本中是按值传递的,这会产生不必要的副本 (as mentioned by TemplateRex in his answer) 的开销。这解释了“性能”的基本原理。
【讨论】:
不错。现在,您能找到一个会破坏现有代码的示例吗? @KonradRudolph 它应该是向后兼容的。第一个 C++11 重载相当于在 C++98 中不提供第二个参数,而第二个 C++11 重载只需要可构造的,而 C++98 已经需要它来调整大小。还是我错过了什么? @TemplateRex 这个答案中的标准引用明确表示情况并非如此:“使用此函数的有效 C++ 2003 代码可能无法编译”。 @KonradRudolph 数组类型可能会中断:***.com/a/12193149/819272 一个简单的重大更改示例是存储指向resize
方法的指针的代码。 void(vector<T>::*)(size_t,T) ptr = &vector<T>::resize
将在 C++03 中编译(模拼写错误)【参考方案2】:
一个原因是默认参数总是被传递,即在这种情况下被复制。正在做
my_vector.resize(1000000)
将复制 100 万个 T
对象。
在 C++11 中,您现在可以选择使用 std::allocator_traits<Alloc>::construct()
函数复制用户提供的值或就地默认插入(即构造)元素。这允许使用 CopyInsertable 但不可 Copyable 的元素调整 vector
的大小。
请注意,此更改已针对具有 resize()
成员(vector
、deque
、forward_list
和 list
)的所有序列容器进行,但不适用于没有 std::string
以默认值参数开头。
更新:除了@AndyProwl 引用的当前标准的附件外,@HowardHinnant 的original defect report 还澄清了:
按值传递 T 的问题在于它可能显着 比通过引用传递更昂贵。反之亦然, 然而,当它是真的时,它通常远没有那么戏剧化(例如 标量类型)。
即使移动语义可用,按值传递此参数 可能很贵。考虑例如向量>:
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 库中发布,没有问题报告 我知道。
【讨论】:
C++11:开发者的力量!我们赋予您选择要复制哪些对象的权利!以上是关于为啥在 C++11 中更改了 std::vector::resize 签名?的主要内容,如果未能解决你的问题,请参考以下文章
C / C ++如何将3维数组存储在内存中以及遍历它的最快方法是啥