Nick Stokes
[...]
struct Foo { explicit Foo(Bar* b = nullptr) : bar(b) {} Bar* bar; };
int getBarValue (const Foo& f) { assert( f.bar ); return f.bar->getValue(); }
boost::multi_index< Foo, indexed_by< hashed_unique < member
>> , hashed_non_unique < global_fun > FooIndex;
void grill() { FooIndex fooIndex;
Bar* b; { auto bWork = make_unique<Bar>(); // ... fooIndex.emplace( bWork.get() ); b = bWork.get(); } fooIndex.erase(b);
// ... }
[...]
I guess my question is a little more subtle.
Yep, now on rereading my answer I see I jumped too fast to a canonical explanation :-)
I think I understand now, but please let me reaffirm: In my example, erase(const key_type&) is being called for the 1-st index (key_type is Bar*), which *could* potentially throw, but in this case this is a simple pointer value and hashing and equality and therefore do *not* throw. But to adjust the 2nd index, MIC does not require the key_extraction on that (which would throw, or in fact, segv), because the node is already identified and is erased. Is that correct?
fooIndex.erase(b) involves hashing and equality comparison for Bar*'s, which as you correctly point out does not throw. Once the element(s) to be erased are identified, no further user-provided function (getBarValue or any other) is invoked, and deletion will succeed. Briefly put, fooIndex.erase(b) does not ever throw and does not ever call getBarValue, if this is what you were after. Joaquín M López Muñoz Telefónica