为啥在 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

基本原理性能、与移动语义的兼容性

对原始特征的影响:对于 vectordequelist,传递给 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() 成员(vectordequeforward_listlist)的所有序列容器进行,但不适用于没有 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维数组存储在内存中以及遍历它的最快方法是啥

在二维矩阵上使用 std::max_element

为啥在单独的线程中修改时我的变量没有改变? c++/升压

迭代 const 容器时编译器会展开“for”循环吗?

为啥只有注释更改的两个程序二进制文件在 gcc 中不完全匹配?

提升变体复制语义