为什么std::vector::resize签名在c++ 11中被改变了?
Why has the std::vector::resize signature been changed in C++11?
std::vector::resize
与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段规定:
Change: Signature changes:
resize
基本原理: 性能,与move语义的兼容性.
对原始特征的影响:对于
vector
,deque
和list
,传递给调整大小的填充值现在被传递引用而不是按值,并且增加了resize的额外重载。有效的c++ 2003代码使用此功能的程序可能无法与本国际标准进行编译。
旧的resize()
函数是从value
复制构造新元素。这使得当vector的元素是默认可构造但不可复制时(您可能希望稍后对它们进行移动赋值),不可能使用resize()
。这解释了"与move语义兼容"的基本原理。
此外,如果您不希望发生任何复制,只希望默认构造新元素,则它可能很慢。此外,在c++ 03版本中,value
参数是按值传递的,这会导致不必要的复制开销(TemplateRex在他的回答中提到)。这解释了"性能"的基本原理。
原因之一是默认参数总是被传递,即在这种情况下被复制。做
my_vector.resize(1000000)
将复制100万个T
对象。
在c++ 11中,您现在可以选择复制用户提供的值或使用std::allocator_traits<Alloc>::construct()
函数在原地默认插入(即构造)元素。这允许调整vector
的大小,这些元素是CopyInsertable而不是Copyable。
请注意,此更改已对所有具有resize()
成员(vector
, deque
, forward_list
和list
)的序列容器执行,但不包括没有默认值参数的std::string
。
更新:除了@AndyProwl引用的当前标准附件外,@HowardHinnant的原始缺陷报告还澄清了:
按值传递T的问题是它可能是显著的比通过引用传递更昂贵。反之亦然,然而,当它是真的时,它通常远没有那么戏剧性(例如for标量类型)。
即使move语义可用,也要按值传递该参数可能会很贵。例如,考虑vector>:
std::vector<int> x(1000); std::vector<std::vector<int>> v; ...
v.resize(v.size()+1, x);
在按值传递的情况下,x被复制一次到resize参数。然后在内部,因为代码可以在编译时不知道向量x的大小调整了多少通常从resize的参数中复制(而不是移动)第二次
通过const-reference传递,上面例子中的x需要只复制一次。在这种情况下,x有一个昂贵的复制构造函数因此,任何可以保存的副本都代表着显著的节省。
如果我们可以有效地处理push_back,那么我们也应该有效地处理调整大小。采用引用参数的调整大小已被编码并在CodeWarrior库中发布,没有任何问题报告
- 变量没有改变?通过向量的函数调用
- 如何改变c++应用程序的视觉效果
- C++在不同线程中改变向量
- 如何访问和改变存储在矢量C++中的对象
- 在C++行尾写一个分号或多个分号是否会改变任何内容
- 为什么字符串的 move() 会改变内存中底层数据的位置?
- 为什么 c++ 动态数组的大小没有改变?
- 为什么提升图库的 read_graphviz() 函数会改变节点的索引
- 在向量内更改变量的值不会改变其在向量外的值
- 为什么 GCC 不能假设 std::vector::size 在这个循环中不会改变?
- 改变或缩放两个正态分布以具有特定的相关系数
- 当我使用CHAR_INFO结构时,控制台会无缘无故地改变颜色
- 为什么我的函数接受"std::string"进行排序不会改变它?
- MFC:你能在CDateTimeCtrl中改变自旋的加速度吗?
- 为什么切换 for 循环的顺序会显著改变执行时间?
- 使用可变参数模板改变模板参数
- C++中物体改变识别的设计模式?
- 通过从构造函数中的'this'复制的指针改变常量对象
- C++11:具有互斥锁的线程看到原子变量的值发生变化,尽管这是唯一可以改变它的代码
- 如果没有重新散列,为什么 unordered_set::begin() 会改变?