【问题标题】:push_backs to a std::vector<std::reference_wrapper<type>>push_backs 到 std::vector<std::reference_wrapper<type>>
【发布时间】:2018-01-27 01:19:20
【问题描述】:

考虑在push_backs 到std::vectorstd::reference_wrappers 的这种尝试:

#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;
}

我希望[] 运算符返回对vi-th 元素的引用,并且从给定here 的可能实现中,我们可以合理地假设附加到@ 的std::reference_wrapper 对象987654330@ 持有指向正确地址v_i[i] 的指针的副本。但是,上面代码的输出是

0
1980603512 //or some other random garbage value

很明显,在循环内构造的std::reference_wrappers 指向的是临时对象。为什么会发生这种情况,附加到s_i 的正确方法是什么?

顺便说一句,我使用的是g++ 5.4.0(带有-std=c++0x 标志)。

【问题讨论】:

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


    【解决方案1】:

    我们可以合理地假设 std::reference_wrapper 对象 附加到 s_i 保存指向 v_i[i]的正确地址

    不,你不能合理地假设。这是因为任何

    v_i.push_back(i);
    

    可能导致重新分配v_i;事实上,你几乎可以肯定这会在某个时候发生在这里。并且任何重新分配都会立即自动使所有现有迭代器和指向向量现有内容的指针无效。

    如果您在std::vector 中保存了指向某些元素的任何普通指针,然后尝试push_back(),这没有什么不同,导致这些指针重新分配和失效。这些指针的任何后续取消引用都会导致未定义的行为。

    这里显示的代码实际上是等效的,只是使用了std::ref 的额外洋葱层来包装整个事物,但会导致逻辑上等效的未定义行为。

    如果您希望在这里避免未定义的行为,唯一可行的方法是充分reserve() 向量,以保证后续push_back() 不会发生重新分配。

    【讨论】:

      【解决方案2】:

      问题是push_back 操作可能会使指向std::vector 元素的迭代器\引用\指针无效。

      来自push_back

      如果新的 size() 大于 capacity() 则所有迭代器和 引用(包括过去的迭代器)无效。 否则只有过去的迭代器无效。

      随着您的std::vector 不断增长,有时新大小会大于当前容量。如上所述,它会导致指向std::vector 元素的引用\指针失效。

      在这种特殊情况下,std::reference_wrappers 无效。

      进一步使用无效的std::reference_wrappers 会导致UB

      【讨论】:

        猜你喜欢
        • 2016-03-31
        • 2023-01-17
        • 1970-01-01
        • 1970-01-01
        • 2020-01-26
        • 2018-02-02
        • 1970-01-01
        • 1970-01-01
        • 2018-10-23
        相关资源
        最近更新 更多