为啥 std::vector::resize(n, src) 按值传递?
Posted
技术标签:
【中文标题】为啥 std::vector::resize(n, src) 按值传递?【英文标题】:Why does std::vector::resize(n, src) pass by value?为什么 std::vector::resize(n, src) 按值传递? 【发布时间】:2011-09-16 02:14:52 【问题描述】:和标题差不多。
std::vector<T>::resize
的规范似乎要求 src
对象按值传递:
void resize(size_type n, T src = T() );
为什么这里不使用对常量对象的引用?
void resize(size_type n, T const& src = T() );
例如,在this question 中,由于在堆栈上创建了一个临时对象,按值传递方面似乎会导致堆栈溢出问题。
如果改为传递对 src
的引用,我们至少能够通过在堆上分配一个临时地址来解决该问题,该临时地址是通过引用传递给 ::resize()
的。
似乎::resize()
与std::vector
的其他成员函数不同步。例如,构造函数按预期通过const&
获取src
对象:
vector (size_type n, T const& src = T(), Allocator const& = Allocator() );
编辑:我挖出了c++03
标准并仔细检查了上面的函数原型没有被错误引用...
【问题讨论】:
常量引用的默认值难道不是仅在 C++11 中引入的新东西吗? @Kerrek 上次我检查时,它在 C++03 中工作。再说一次,也许我错了。 @Kerrek - 刚刚通过2003
标准进行了测验,T const& = T()
模式似乎在那里......
@Kerrek,如果向量构造函数的规范是正确的,那么它必须被允许。唯一的问题是给出的规范是来自标准还是来自其他不正确的来源。
是的,那只是我的错误。不知道……不过,这是个好问题!有趣的是,底层分配器确实通过常量引用而不是复制来获取原型。
【参考方案1】:
它是a mistake in the Standard Library specification。它在 C++11 中已修复; std::vector
现在有两个 resize
成员函数声明为:
void resize(size_type sz);
void resize(size_type sz, const T& c);
两者的区别在于,如果resize后容器的大小变大了,第一个重载值初始化新元素,而第二个副本构造它们;此模式用于其他成员函数和其他容器中。
【讨论】:
@Kerrek SB:事后诸葛亮的好处 :) 唯一的问题是为什么这么简单的更改花了这么长时间...... @Matthieu - 我喜欢缺陷报告表明它在c++98
c++98
...
是的,push_back(v[0])
必须工作对我来说是个新闻。因此 C++11 调整大小必须:1) 分配一个新的内部缓冲区,2) 复制构造新元素,3) 移动旧元素,4) 破坏元素并释放旧缓冲区。对? 2前不能做3,push_back
也不能。
@Darren:DR 说“在 C++98 批准之前”。这留下了 C++98 已经在 FDIS - Final Draft 中的可能性。
@Steve - 当然您可以通过push_back(v[0])
或resize(n, v[0])
等进行自我分配。我认为该过程将是:1)检查自我分配,如果是的话,找到index 在我们正在分配的当前向量存储中(因为在 realloc 之后索引是不变的),2)重新分配一个新缓冲区,3)copy-ctor 新元素(来自 v[index]
如果 self-分配),4)移动旧元素,5)销毁并释放旧缓冲区。 push_back
和 resize
在这里应该按照类似的方式工作 - 我的 msvc 2010
已经做了类似的事情......以上是关于为啥 std::vector::resize(n, src) 按值传递?的主要内容,如果未能解决你的问题,请参考以下文章
std::vector::resize() 与 std::vector::reserve()
如果 std::vector::resize 的 size 参数等于当前大小怎么办?