
On Sep 24, 2009, at 11:23 AM, Thorsten Ottosen wrote:
Howard Hinnant skrev:
On Sep 24, 2009, at 10:02 AM, Thorsten Ottosen wrote:
It doesn't quite address my first issue though, namely that I need to construct the mapped value in the node, and then compute the key from this mapped value (after some modification).
I think if the node_ptr class had
a) a forwarding (Key,Value) constructor
b) an emplacing constructor that constructed the pair with (Key,...)
then I could do exactly what I needed :-) With what allocator would the node_ptr allocate the node?
Ok, I guess that is why I originally spoke about the following interface:
typedef ... map; map m; map::node_ptr p = m.get_node_ptr(<like emplace, but only for constructing the mapped value>); p->pair.first = modify( p->pair.second ); m.insert( boost::move(p) );
So get_node_ptr( ... ) with two overloads would be needed.
first ::new (&p->first) key_type(modify( p->second )); // tell node_ptr that it is now responsible for p->first
This is effectively the same thing as: typedef ... map; map m; map::node_ptr p = m.remove(m.emplace_hint(m.begin(), my_special_cheap_key_value, mv1, mv2)); p->first = modify( p->second ); m.insert( boost::move(p) ); The main differences are: 1. map never exposes a partially constructed pair to the client. 2. the onus is on the client to figure out how to cheaply and temporarily construct a key (when he needs to). 3. exception safety handling is much simplified. It is a tradeoff that I think is good. Having an interface that exposes a partially constructed object to everyone would be bad (for almost everyone). Having an interface that makes it more difficult for a few clients to extract a little more performance, isn't good, but it is better than exposing partially constructed objects. These partially constructed objects would need more complicated exception safety protection, which could only be partially encapsulated by the node_ptr: typedef ... map; map m; map::node_ptr p = m.get_node_ptr(<like emplace, but only for constructing the mapped value>); // p->first not constructed here // if construction fails, ~node_ptr() only destructs p->second, not p- p.first_constructed(true); m.insert( boost::move(p) ); -Howard