push_backs到std :: vector <std :: reference_wrapper <type>&gt;

时间:2018-01-27 01:19:20

标签: c++ c++11 stl c++14

考虑push_backstd::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_wrappers_i标志)。

2 个答案:

答案 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