为啥 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++98c++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_backresize 在这里应该按照类似的方式工作 - 我的 msvc 2010 已经做了类似的事情......

以上是关于为啥 std::vector::resize(n, src) 按值传递?的主要内容,如果未能解决你的问题,请参考以下文章

std::vector::resize() 与 std::vector::reserve()

如果 std::vector::resize 的 size 参数等于当前大小怎么办?

为啥(n = 0)== 0?

为啥 iTextSharp 阅读页面 1..N 而不是 N?

为啥对于输出流,'\n' 优于 "\n"?

为啥插入 ListMap O(n)?