【问题标题】:Why are references ever invalidated?为什么引用总是无效的?
【发布时间】:2013-02-23 21:17:10
【问题描述】:

所以我看到this question,基本上说引用和迭代器一起失效。

我明白为什么在某些情况下迭代器会失效,但是为什么引用会失效

从实际的角度来看,我不明白为什么需要这样做。

这只是一个设计决定还是有一些实际原因?

编辑:澄清一下,据我了解底层结构,它只是指向需要重新分配的数据的指针(数据(以及对它的引用)可以保持不变)。对吧?

一些测试代码:

#include <vector>
#include <iostream>
using namespace std;

int main()
{
    vector<string> yourVect;
    yourVect.push_back("def");
    vector<string>::iterator iter = yourVect.begin();
    const string& ref = *iter;
    yourVect.insert(yourVect.begin(), "abc");
    cout << ref << endl; // !! --- doesn't work - why ?? --- !!
    cout << *iter << endl; // obviously doesn't work
}

【问题讨论】:

  • 向量可以重新分配
  • 当它被初始化的底层动态分配被从它下面抹去时,你认为你的引用是什么“引用”?
  • 我不明白,你怎么能在重新分配后将对象移动到新位置并仍然期望旧的仍然存在?!
  • @Dukeling 查看 Matteo 的更新答案。引用比指针更具限制性,并且遵循更严格的规则。而且您的建议对指针也无效,所以我仍然不明白为什么您认为它会受到引用的支持。 一些容器以您描述的方式支持实时引用,但向量不是其中之一。对于这样的容器,请参见 std::deque,但仅当插入物位于任一端时。

标签: c++ stl reference iterator


【解决方案1】:

如果您在向量的开头插入一个字符串,则所有数据都必须向前移动一个位置,并且如果vector 的容量耗尽,则vector 将不得不重新分配。

所以,最好的情况是引用现在引用不同的数据,最坏的情况是引用无效的内存位置:如果向量重新分配,分配一个新的内存块,复制旧的数据1 sup> 在新块中,旧块被释放;由于所有旧引用都指向旧块内的内存位置,因此它们都将无效。

保证涉及“最坏情况”,这就是为什么不保证在insert 操作之后,引用仍然有效。或者,换一种说法,向量中的插入可能使迭代器和引用无效。

另外,我不明白为什么您认为引用和迭代器之间的这种行为存在很大差异 - vector 迭代器通常只是指向引用的 vector 位置的指针(通常隐藏在实现定义的类),所以它或多或少与参考相同。


  1. C++11 中的 IIRC 实际上它们被“移动”了(如在std::move 中);这不会改变旧引用将继续指向随后释放的内存这一事实。

【讨论】:

  • @Dukeling:见编辑回答(特别是第二段)。
  • @Dukeling:是的,这实际上是vector 的要点之一(一大块顺序内存,而不是每个对象的单独内存块)。相反,如果你想要一个指针向量,你只需要请求它(创建一个vector&lt;T *&gt;);顺便说一句,在 Boost 中有一些方便的类来管理存储在指针 vector 中的对象的生命周期。
  • @Dukeling 标准规定必须如此。特别是在 C++11 § 23.3.6.1p1 “向量的元素是连续存储的,这意味着如果 v 是向量,其中 T 是 bool 以外的某种类型,则它服从恒等式&v[n] == &v[0] + n 对于所有 0
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-01-06
  • 2021-02-19
  • 2021-03-16
  • 1970-01-01
  • 2016-11-02
  • 1970-01-01
  • 2016-08-10
相关资源
最近更新 更多