8

I have two sets and an iterator to an element of a:

set<unique_ptr<X>> a, b;
set<unique_ptr<X>>::iterator iter = find something in a;

I would like to remove the element pointed by iter from a and insert it into b. Is it possible? How?

Yakov Galka
  • 70,775
  • 16
  • 139
  • 220
  • @black: I believe that the question is self-contained. If you're smart enough to answer, the problems should be self evident to you. – Yakov Galka May 05 '15 at 11:08
  • In my view, though, the issue should be evident in the question and should not require you to code something to show up. The problem I see might be different from what you see. I get problems with `const`ness, what about you? – edmz May 05 '15 at 11:20
  • 2
    @black: You don't need to code anything. In fact I did not even try to compile any code because I know well enough the language to know that insert and erase won't work. The question is addressed to those who know the C++ standard well enough and may point me to a particular part of the std::set interface, or a combination thereof, which would accomplish what I need. The question is there, and if you think that every problem on SO translates to a compiler error, too bad for you. – Yakov Galka May 05 '15 at 12:04

1 Answers1

2

Well, I suspect there is no normal way to do it. But there is always a non-normal one :) You can do the following:

auto tmp = const_cast<std::unique_ptr<std::string>&&>(*iter);
a.erase(iter);
b.insert(std::move(tmp));

Ok, the very first line violated set invariant and it is horrible but as far as I understand it should not be a problem since on the very next line we remove this evil node from the set.

ixSci
  • 13,100
  • 5
  • 45
  • 79
  • 1
    Won't this invalidate the unique_ptr upon erasure ? – Tasos Vogiatzoglou May 05 '15 at 10:08
  • @TasosVogiatzoglou, no it won't. We moved the object from set `a` to `tmp` and upon erasure set `a` contains `moved-from` `unique_ptr` object. – ixSci May 05 '15 at 10:11
  • Oh, ok. As I was reading it I thought that upon erasure the deleter is called. – Tasos Vogiatzoglou May 05 '15 at 10:15
  • 2
    Well, this violates the `set` invariant so badly that I cannot be sure that every rb-tree implementation will result in an ordered rb-tree *after* the erasure of the violating node... Guess it's impossible then... – Yakov Galka May 05 '15 at 11:06
  • Actually I *can* imagine rb-tree implementation that will fail on this code. Think of one that does not store parent pointers and does a search from the root to do the erasure instead. Not sure it is allowed by the standard, but otherwise it is a legit rb-tree. – Yakov Galka May 05 '15 at 11:12
  • I don't think any reasonable implementation would use value comparison on iterator erase. Even if it traversed the tree from the root it would use some internal data which is stored in iterator to make comparison. It is just stupid to make value comparisons in this case. But anyway, as I said my solution is not pretty but I can't come up with something else. Except coping what is stored in the `unique_ptr` to create a new one. But it is not what you asked for. – ixSci May 05 '15 at 11:50