1

Suppose I have a c++ std::list object containing a few elements and an iterator it to one of the elements. How can I remove this element from the list but still be able to access it? In other words, I want it delinked from the list, but not deallocated.

Curiously, using list::erase does seem to achieve this:

#include <iostream>
#include <cstdio>
#include <list>

using namespace std;

int main() {
    std::list<int> a;
    a.push_back(1);
    a.push_back(2);
    a.push_back(3);
    auto it = (--a.end());
    a.erase(it);
    cout << *it << endl;   /// outputs '3' anyway, without any error
}

But I assume this isn't really safe?

Questions:

  1. Is it a guarantee behavior that an element erased by list::erase is still accessible by the original iterator?

  2. If yes, how can I deallocate its memory?

  3. If no, how can I erase some element without deallocating its memory and be able access it after erasal?

ihdv
  • 1,927
  • 2
  • 13
  • 29
  • `How can I remove this element from the list but still be able to access it? In other words, I want it de-linked from the list, but not deallocated.` This is not possible. Its either in the list or it isn't, there is no inbetween. `If no, how can I erase some element without deallocating its memory and be able access it after erasal?` Copy it out? – tkausl Jul 02 '22 at 04:59
  • @tkausl Copying might be a bit troublesome for me. Since I have more than one iterators pointing to the same element. – ihdv Jul 02 '22 at 05:01
  • @ihdv See the same example in the [dupe](https://stackoverflow.com/a/40899891/12002570) `test.erase( it ); std::cout << *it << std::endl;` – Jason Jul 02 '22 at 05:04
  • @AnoopRana I see. So `it` in my case is in fact invalid? I noticed that in the link you provided all iterators after the the erased `it` become invalid. But since I am using a `list`, can c++ guarantee all other iterators except the erased one to still be valid? – ihdv Jul 02 '22 at 05:20
  • @ihdv You can splice the element onto another list. – john Jul 02 '22 at 05:39
  • @ihdv "*So `it` in my case is in fact invalid?*" - after the erase, yes. "*all iterators after the erased `it` become invalid*" - incorrect. In `std::list`, only iterators to the erased element are invalidated. "*since I am using a `list`, can c++ guarantee all other iterators except the erased one to still be valid?*" - yes. That is part of the design of `std::list` dictated by the standard. – Remy Lebeau Jul 02 '22 at 05:40

1 Answers1

6

This can be done provided you don't mind using a second list to receive the erased item

auto it = (--a.end());
std::list<int> b;
b.splice(b.end(), a, it);
cout << *it << endl;   /// outputs '3'

splice removes the it element from list a and adds it to the end of list b. It's a constant time operation and does not invalidate any iterators.

john
  • 85,011
  • 4
  • 57
  • 81
  • Incidentally `splice` can also be used as a fast way to reorder items within a single list. – john Jul 02 '22 at 05:51