考虑push_back
到std::vector
std::reference_wrapper
的{{1}}次尝试:
#include <iostream>
#include <vector>
#include <functional>
int main()
{
std::vector<int> v_i;
std::vector<std::reference_wrapper<int>> s_i;
for(int i=0;i<10;++i)
{
v_i.push_back(i);
s_i.push_back(std::ref(v_i[i]));
}
std::cout<<v_i[0]<<std::endl;
std::cout<<s_i[0].get()<<std::endl;
return -1;
}
我希望[]
运算符返回对i-th
的{{1}}元素的引用,并且根据here给出的可能实现,我们可以合理地假设{附加到v
的{1}}对象包含指向std::reference_wrapper
正确地址的指针副本。但是,上面代码的输出是
s_i
很明显,在循环内构造的v_i[i]
指向临时对象。为什么会发生这种情况,以及追加到0
1980603512 //or some other random garbage value
的正确方法是什么?
顺便说一下,我使用std::reference_wrapper
(s_i
标志)。
答案 0 :(得分:4)
我们可以合理地假设std :: reference_wrapper对象 附加到s_i保存指向指针的指针的副本 正确的地址v_i [i]
不,你无法合理地假设这一点。这是因为任何
v_i.push_back(i);
会导致重新分配v_i
;事实上,你几乎可以保证在某种程度上会发生这种情况。并且任何自动重新分配都会立即使所有现有的迭代器和指向vector的现有内容的指针无效。
如果您将任何普通指针保存到std::vector
中的某些元素,然后尝试push_back()
,则会导致重新分配并使这些指针失效,这没有什么不同。任何后续取消引用这些指针都会导致未定义的行为。
这里显示的代码在实质上是等效的,只是使用std::ref
的额外洋葱层来包装整个事物,但导致逻辑上等效的未定义行为。
如果你想在这里避免未定义的行为,唯一可行的方法就是充分reserve()
向量,以保证后续push_back
()s不会发生重新分配。
答案 1 :(得分:2)
问题是push_back
操作可能会使std::vector
元素的迭代器\ references \ pointer失效。
来自push_back:
如果新的size()大于capacity()那么所有的迭代器和 引用(包括过去的结束迭代器)无效。 否则只有过去的迭代器无效。
随着您的std::vector
越来越多,有一段时间新尺寸大于当前容量。如上所述,它会导致std::vector
元素的引用\指针无效。
在这种特殊情况下,std::reference_wrapper
无效。
进一步使用无效的std::reference_wrapper
会导致 UB 。