On Mon, 11 Oct 2004 10:19:54 -0600, David M. Jones <djones@keymark.com> wrote:
- The container itself would act more or less identically to std::list; - The iterators on the container would act like boost::weak_ptr in
would know that they are invalid when the list element that they
"Caleb Epstein" <caleb.epstein@gmail.com> wrote in message news:<989aceac041012063240b6aa3@mail.gmail.com>... that they point to is
removed.
Can't you just do this with a std::list<boost::shared_ptr>? You can convert the *iterators to weak_ptrs as needed. Or am I missing something?
There are a couple of reasons that std::list<boost::shared_ptr> is less than ideal. First, using the algorithms becomes cumbersome/annoying. Instead of being able to write std::list<boost::shared_ptr<int> > lst; // ... Populate the list int i; // ... Set the value of i std::list<boost::shared_ptr<int> >::iterator = std::find(lst.begin(), lst.end(), i); I instead need to create a function object to represent a boost::shared_ptr<int> having the desired value and then use find_if(). Second, I would lose the ability to store iterators and then check them later for validity. Suppose that I have a std::list<boost::shared_ptr<int> > named lst and I have two std::list<boost::shared_ptr<int> >::iterator objects it1 and it2 that happen to reference the same node in the list. If I call lst.erase(it1) then it2 also becomes invalid. If I call boost::weak_ptr<int>(*it2) I get an error because I cannot dereference the iterator because it is already invalid. This is how std::list objects are supposed to work but what I want to be able to do is now call something like it2.expired() to determine that the node being refered to by it2 is not invalid/expired/removed. One way to get around this is to store boost::weak_ptr objects derived from std::list<boost::shared_ptr>::iterator objects instead of storing it1 and it2 directly. But then I lose the advantage of having stored iterators: I cannot (after checking for expiration and being at the end of the list) call operator++() to move the iterator forward. Fundamentally, I don't want to be storing a "list of nodes of shared pointers of objects" but a "list of nodes of objects whose pointers to each other are shared pointers". And I want the iterators to be weak pointers to the nodes. Potentially a way to do this would be to write a custom allocator my_alloc that declares typedef boost::shared_ptr pointer; and then create a std::list<T, my_alloc<T> > This works because std::list uses the allocator rebinding mechanism to call my_alloc<node<T> > rather than my_alloc<T>. (In fact, my_alloc<T> is never used to allocate anything in std::list<T>!) However, there is a problem because the interface (concept a la Austern) of boost::shared_ptr is different than that of a regular pointer. So when the std::list code tries to call _Myhead = 0; I get a compiler error. (I am using MSVC 7.1: although this particular error may be STL implementation dependent, I do believe that the problem I am describing will occur with any STL implementation.) But I digress... The question of why the boost::shared_ptr interface/concept does not conform to that of a normal pointer is probably a topic for a separate posting.
"David Jones" <djones@keymark.com> wrote in message news:0B1A338441015A44AB55AAC0083EB78D64F5F0@exchange.keymark.com... | There are a couple of reasons that std::list<boost::shared_ptr> is less | than ideal. | | First, using the algorithms becomes cumbersome/annoying. | Second, I would lose the ability to store iterators and then check them | later for validity. your first requirement fits the smart container library perfect. your second requirement is really not there. | Fundamentally, I don't want to be storing a "list of nodes of shared | pointers of objects" but a "list of nodes of objects whose pointers to | each other are shared pointers". And I want the iterators to be weak | pointers to the nodes. This is certainly an interesting problem senario. I have still to decide a specialization of my containers for smart pointers; eg, ptr_vector< boost::shared_ptr<T> > can be made to do what we find most important. The question of whether to have iterator invalidation is interesting and I bet it can be done, but is it worth the price? Why not just stored a shared_ptr<T> instead of the iterator? Some design alternatives could be typedef ptr_list< shared_ptr<T> > list_t; list_t list; list.weak_begin(); // returns indirected iterator as you want list.begin(); // returns normal indirected iterator list_t::observed_ptr sp = list.observe( iterator ); // returns shared_ptr to element list_t::weak_observed_ptr wp = list.weak_observe( iterator ); // returns weak_ptr to element br Thorsten
participants (2)
-
David Jones
-
Thorsten Ottosen