[smart cont.] Const semantics in boost::ptr_map vs. std::map

Two issues: (1.) I stumbled upon a strange inconsistency in boost::ptr_map's iterator interface. I've attached some demonstration code that shows the problem. (2.) Given a (nonempty) const std::map<X, Y*> object, it is possible to retrieve a Y& from it. Given a const boost::ptr_map<X, Y> object, it is not possible (without casting) to retrieve a Y& from it. Thus, it is not possible (in general) to refactor code which uses a std::map<X, Y*> combined with manual ptr_map-like lifetime/ownership management to use a boost::ptr_map<X, Y> without changing const semantics. Was this effect intentional? If so, why was this approach chosen? It seems like ptr_map attempts to "hide" the level of indirection that a standard container of pointers has. While this may be desirable, I think it should be mentioned in the documentation since it can come as a surprise to people (like me) who actually try to perform the refactoring mentioned above. Eelis #include <map> #include <boost/smart_container/ptr_map.hpp> typedef std::map<int, int *> M; typedef boost::ptr_map<int, int> N; void f (M & m) { M::iterator i = m.begin(); M::iterator const ci = i; int & a = *(i->second); // ok int & b = *(ci->second); // ok } void g (N & n) { N::iterator i = n.begin(); N::iterator const ci = i; int & a = *i; // ok int & b = *ci; // error: invalid initialization of reference of type 'int&' from expression of type 'const int' }

"Eelis van der Weegen" <eelis@eelis.net> wrote in message news:cpd4kr$dr2$1@sea.gmane.org... | Two issues: | | (1.) I stumbled upon a strange inconsistency in boost::ptr_map's | iterator interface. I've attached some demonstration code that shows the | problem. As for the code, then I think you are right. Had you written const_iterator and not const iterator, I would expect differently. So this is an error in my code. | (2.) Given a (nonempty) const std::map<X, Y*> object, it is possible to | retrieve a Y& from it. Given a const boost::ptr_map<X, Y> object, it is | not possible (without casting) to retrieve a Y& from it. yes. but that cast is a bad idea; add const the right places instead. | Thus, it is not possible (in general) to refactor code which uses a | std::map<X, Y*> combined with manual ptr_map-like lifetime/ownership | management to use a boost::ptr_map<X, Y> without changing const semantics. | | Was this effect intentional? yes. All the containers propagate constness. | If so, why was this approach chosen? to make it easier to write const-correct programs. there has been discussion about this from time to time, but in general my impression has been than propagation of constness was appropriate for non-shared resources. | It seems like ptr_map attempts to "hide" the level of indirection that a | standard container of pointers has. yes, some have suggested to call them indirect containers instead. | While this may be desirable, I think | it should be mentioned in the documentation since it can come as a | surprise to people (like me) who actually try to perform the refactoring | mentioned above. yes, it will be mentioned (if it isn't all ready). Thanks Thorsten

Thanks for your (quick) response. Here's another snippet that fails to compile (on MingW-gcc 3.4.2), while it really should: #include <boost/smart_container/ptr_map.hpp> struct S { int x; }; void f (boost::ptr_map<int, S>::iterator i) { (*i).x; // ok i->x; // error: operator-> is inaccessible } Eelis

"Eelis van der Weegen" <eelis@eelis.net> wrote in message news:cpdcd0$sec$1@sea.gmane.org... | Thanks for your (quick) response. Here's another snippet that fails to | compile (on MingW-gcc 3.4.2), while it really should: | | #include <boost/smart_container/ptr_map.hpp> | | struct S { int x; }; | | void f (boost::ptr_map<int, S>::iterator i) | { | (*i).x; // ok | i->x; // error: operator-> is inaccessible | } yes, also an error AFAICT, Thanks -Thorsten

And here's another snippet that fails to compile: #include <boost/smart_container/ptr_vector.hpp> #include <boost/smart_container/ptr_map.hpp> struct S {}; void f () { typedef boost::ptr_vector<S> V; typedef boost::ptr_map<int, S> M; V v1; V v2 (v1.clone()); // ok, taken from Example 3 ( // "Copy-semantics of smart containers") M m1; M m2 (m1.clone()); // error: no matching function for call to ` // std::map<...>::map(std::allocator<S*>)' } Eelis
participants (2)
-
Eelis van der Weegen
-
Thorsten Ottosen