【问题标题】:Why does vector::erase() not invalidate a reference to the erased element?为什么 vector::erase() 不会使对已擦除元素的引用无效?
【发布时间】:2014-04-02 16:25:19
【问题描述】:

考虑以下代码:

vector<int> test = { 0, 1, 2 };
test.push_back(3);   
int& last = test.back();
test.pop_back();    //now last_elem_ref should be invalid, right?
3 == last; //evaluates to true o.O
last = 5;  // this works just as fine 

我知道不存在对任何内容的引用,但我不知道这是如何工作的。 C++ 没有垃圾收集器或引用计数(当然除了智能指针),所以为什么当对象的所有者转储对象时对象没有被销毁?

还是被销毁了,引用甚至不再引用值了?

什么时候销毁,例如它占用的内存何时会被释放?(我个人的猜测是对象的最后一个引用超出范围。)

【问题讨论】:

  • 使用last 是未定义的行为。你不应该对任何结果感到惊讶。
  • @chris 澄清一下,从向量中擦除后使用last 是未定义还是一般未定义?
  • @iFreilicht,在它变成一个悬空引用之后。
  • 在任何可能导致向量元素重定位的操作之后。例如。 push_back - 如果没有足够的内存并且会发生重定位,引用将无效。 pop_back 但绝不应该触发重定位,所以从技术上讲它不是 UB。

标签: c++ vector stl reference


【解决方案1】:

我知道不存在对任何东西的引用

是的:就像指针一样,如果引用的对象被销毁,引用可能会失效并悬空。使用无效的引用会产生未定义的行为。

为什么当它的所有者倾倒对象时它没有被销毁?

是的。但是销毁一个对象并不一定会使它占用的内存无法访问。在这种情况下,内存仍然由vector 管理,访问它可能会得到旧值,因为没有任何东西覆盖它。或者它可能会导致某种其他形式的未定义行为。

什么时候销毁,例如占用的内存什么时候释放?

当向量被销毁,或者当它重新分配它的数组时,内存将被释放。不过它可能仍然可以访问;小块通常返回到堆中以供重用,而不是从进程的内存空间中取消映射。

我个人的猜测是对象的最后一次引用超出范围。

没有。正如您所说,C++ 中没有引用计数。自动对象在超出范围时被销毁,而动态对象在它们被显式销毁时被销毁,而不管对它们的任何引用。

【讨论】:

  • @iFreilicht:当向量重新分配时,所有对元素的引用都将失效。但它不会在这里重新分配:这只发生在它需要增长时,或者当你调用shrink_to_fit 时。在这种情况下,擦除元素(通过erasepop_back)会使对被擦除元素的引用无效。
  • 接受,非常感谢!这个答案很彻底,没有什么可质疑的。荣誉奖:this answer 这确实有助于理解问题。
【解决方案2】:

引用仍然指向值所在的内存位置,并且尚未更改该内存位置的内容。

这是未定义的行为 - 无法保证该内存的内容,甚至无法保证在不崩溃的情况下读取它。

【讨论】:

    【解决方案3】:

    实际上,内存仍然被分配,但这并不意味着您可以使用它:-) 这是std::vector 如何在内部管理内存的直接结果。内存永远不会被释放,除非你clear()

    如果你尝试另一个push_back,last 引用的值应该会受到影响。

    再次明确,不要依赖这个,这是一种不好的做法,并且可能是未定义的行为。

    【讨论】:

    • push_back() 的那个小提示是我需要理解的一切。我忘记了向量分配的内存比其元素占用的内存多。非常感谢你!是的,我永远不会依赖它,因为我什至没想到它会那样做。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-27
    • 2020-05-10
    • 2011-09-30
    • 1970-01-01
    • 2017-04-15
    • 2018-08-19
    相关资源
    最近更新 更多