4

I am writing a template class similar to std::map. Currently I'm working on implementing a function equivalent to std::map::extract(). This should return a node handle with its own function node_type::key(), that returns a non-const reference to the key. This therefore allows changing the key associated with a mapped object and thus avoids moving the mapped object.

std::map exposes its value as std::pair<const Key,T>, but somehow allows changing the Key object through a node_type object. I don't understand how STL implementations deal with this? I am lead to believe that they include const_cast conversions, but all resources I read heavily discourage the use of const_casts for fear of undefined behaviour, especially when changing the value afterwards.

This resource invokes "implementation magic".

How can I implement std::map::extract() without causing undefined behaviour?

Related Questions

chiasmos
  • 110
  • 7
  • 2
    Implementations can avoid undefined behavior by simply defining it for a specific use case. That's the "implementation magic". – BoP Feb 09 '23 at 11:28
  • `std::map` probably does not handle `std::pair` internally but a better suited node type (I've no proof of that , it's just my guess). – Fareanor Feb 09 '23 at 11:29
  • @Fareanor But that would mean that any access to the pair would require a copy of the value – gerum Feb 09 '23 at 11:30
  • @Fareanor `std::map`s iterator dereferences to `std::pair`, meaning that there must be an underlying `pair` object, no? – chiasmos Feb 09 '23 at 11:38
  • @BoP Then my question would be, how do I do that? – chiasmos Feb 09 '23 at 11:38
  • @gerum You're right, it invalidates my guess. In that case, I don't know how it is done (but the given answer seems to give a good explanation). – Fareanor Feb 09 '23 at 12:05
  • 1
    @chiasmos "implementation magic" is created by having a talk with the guys writing the compiler. Perhaps they can add a [__builtin_x](https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html) function for the x you need. Or let you have a `#pragma magic make_this_work` :-) – BoP Feb 09 '23 at 17:36

1 Answers1

3

How can I implement std::map::extract() without causing undefined behaviour?

You can't. The standard specifies behaviour that is not implementable in portable C++.

An implementer (of C++) will be required to have implementation-defined additional guarantees, which need not be exposed to user code, to handle this requirement. This is colloquially known as "implementation magic".

What you could do is write a proposal, submit it to the committee, and get it voted into a future standard; such that there is a mechanism by which this can be accomplished. implicit-lifetime-types that arrived in C++20 did a similar thing to the requirements on std::vector::data.

Caleth
  • 52,200
  • 2
  • 44
  • 75
  • Interesting. This seems to be the answer I'm looking for, thank you. Would you care to elaborate what you mean by "portable" c++ here? I guess it means that the implementation is platform-dependant, but why must that be? – chiasmos Feb 09 '23 at 22:37
  • 1
    @chiasmos When you start with a `std::pair`, and some valid pointers and references to those objects, turn it into a `std::pair` and then back into a `std::pair`, the pointers and references still have to be valid. The rules about object lifetimes don't allow that. Whatever solution an implementer might come up with *must* be tied to the rest of the implementation – Caleth Feb 10 '23 at 09:21