【问题标题】:invalid iterator with random access iterators with deque带有随机访问的无效迭代器 带有双端队列的迭代器
【发布时间】:2012-11-20 13:28:27
【问题描述】:

我正在阅读 Scott Meyers 的有效 STL。在第 1 项中,作者提到了如何在各种容器中进行选择,下面是我难以理解的文本 sn-p。

拥有一个随机访问的序列容器会有所帮助吗 没有指向数据的指针和引用的迭代器 只要没有任何内容被擦除并且插入发生就无效 只在容器的末端?这是一个非常特殊的情况,但如果 这是你的情况,双端队列是你梦想的容器。 (有趣的是,deque 的迭代器在插入时可能会失效 仅在容器的末端制作。 deque 是唯一的标准 STL 容器,其迭代器可能无效 使其指针和引用无效。)

我对上述文字的问题

  1. 作者在上述上下文中的指针和引用是什么意思,它与迭代器有什么不同?

  2. 当只在末尾进行插入并且我们仍然有有效的指针和引用时,如何使双端队列的迭代器失效?

要求用简单的例子回答以上两个问题。

感谢您的时间和帮助。

【问题讨论】:

  • 在开头或结尾插入不会改变内容的实际内存位置,因此任何指针或引用都会继续指向正确的对象。但是,如果迭代器存储为例如从一开始的偏移量,则插入将使任何现有的迭代器具有错误的偏移量。然而,这是一个完整的猜测,只是大声思考。

标签: c++ stl


【解决方案1】:

第一部分的意思是这样的:

deque<int> foo(10, 1); // a deque with ten elements with value of 1
int& bar = foo.front(); // reference
int* baz = &foo.front(); // pointer
deque<int>::iterator buz = foo.begin(); // iterator
deque.push_front(0); 
// At this point bar and baz are still valid, but buz may have been invalidated

第二部分已在此处详细介绍:

Why does push_back or push_front invalidate a deque's iterators?

【讨论】:

    【解决方案2】:

    迭代器通常用于“循环”标准库容器的元素,就像您对数组索引所做的那样,例如在for 循环中。

    迭代器无效的原因有很多。发生这种情况的一种常见情况是当您使用 for 循环时,如下所示:

    std::deque<int> c;
    
    for(std::deque<int>::iterator i = c.begin(); i != c.end(); ++i) {
        // do some stuff to the deque's elements here
    }
    

    在上述循环结束时,迭代器i 将指向一个“元素”双端队列中最后一个实际元素之后的一个块。如果您尝试做类似的事情

    *i = 88;
    

    在上述for 循环结束之后,这将是一个问题,因为容器不“拥有”内存i“指向”。

    但 Meyers 可能谈论的是标准将 deque 的大部分实现留给设计者。双端队列通常实现为包含多个元素的内存块的链表,因此与向量不同,不能保证元素在内存中彼此相邻。此外,迭代器必须包含有关这些“块”的信息,以便它们可以顺利地遍历它们(即迭代器不仅仅是指针)。

    例如,如果我 push_back() 一个新元素,但“最后”一块内存中没有更多空间,那么 deque 将需要为新元素(以及未来添加的元素)分配一个新的内存块到最后)。由于我之前使用的迭代器可能不“知道”这个新的内存块,它可能是无效的。

    另一方面,引用和实际指针将在此上下文中用于引用/指向容器中的各个对象。如果我写

    int& j = *c.begin();
    

    那么 j 是对c 的第一个元素的引用。如果我这样做了

    c.push_front(74);
    

    j 仍然引用之前的第一个元素,即使它不再位于双端队列的前面。

    然而,如果你在双端队列的中间插入一些东西,那么你很可能会有效地分割那些连续的内存块并试图挤压你的新里面的元素。为了腾出空间,必须在内存中移动一侧或另一侧的元素(并且可能需要分配新的内存)。这必然会使对插入“一侧”的元素的指针/引用无效。由于插入元素的确切空间由实现者决定,因此对于任何指针/引用,无论插入的位置在哪里,所有赌注都是无效的。

    【讨论】:

    • 如果我们 push_front 我们可能会重新排列容器或分配新的内存垃圾,那么即使它不再位于队列的前面,引用如何有效?
    • @venkysmarty 该引用是有效的,因为它仍然引用一个有效的元素。该元素不再位于最前面,但引用仍然指向它。 push_front 永远不会重新排列容器,但它可能会分配新的内存。重要的部分是曾经位于最前面的元素保留在内存中。只是“前”的地址变了。
    猜你喜欢
    • 2019-10-07
    • 2015-02-10
    • 2019-12-06
    • 2022-11-14
    • 2017-05-20
    • 1970-01-01
    • 2016-07-19
    • 2011-09-21
    相关资源
    最近更新 更多