|
Boost : |
From: Thorsten Ottosen (nesotto_at_[hidden])
Date: 2004-09-26 14:34:22
Hi Pavel,
Thanks for your review.
| I vote weak YES to accept smart containers into Boost.
sounds good :-)
| In current state the library is missing:
| - small readable code examples
ok, what do you find particular non-readable about all the examples in the
example section?
| - support for object factories
ok, I'm 100% how you imgine they should look like, so please give some
examples.
| 0. Name of the library should be "Smart Containers"
| (note the plural).
ok.
| _____________________________________________________
| 1. It would be nice the very first sentence of docs
| being something as:
|
| "Smart Containers are STL compatible containers
| holding and owning object pointers."
agree, although I not sure what "xompatible" should mean.
| _____________________________________________________
| 2. docs: the link to license file may be better local.
ok, why?
| _____________________________________________________
| 3. docs, Introduction: the reference to shared_ptr
| may be hyperlinked.
agree.
| _____________________________________________________
| 4. docs, Introduction:
|
| " in case of a map"
|
| ==>>
|
| " in case of a associative containers like map"
well, in case of a set, it is the key_type that is allocated, not the
mapped_type.
| _____________________________________________________
| 5. docs, Introduction: sentence
|
| "the objects in an exception safe manner."
|
| may mention what type of exception safety smart
| containers have or take from.
the issue here is that std::container<T*> is not exception-safe, ie, will not
even give the
basic exception-safety guarantee. So exception-safety means at least the BESG,
possibly more.
The no one policy for all functions in the entire library.
| _____________________________________________________
| 6. docs, Introduction:
|
| "fool proof pointer storage"
|
| ==>>
|
| "pointer storage safer to use mistakes"
|
|
| "Foool proof" suggests _absolute_ ideal.
he true, this "fool proof" is impossible in C++.
| _____________________________________________________
| 7. docs, Introduction: Assignable and
| Copy Constructible could be hyperlinked.
ok, don't people know this?
| _____________________________________________________
| 8. docs, Introduction:
|
| "Usually faster than using containers of smart pointers"
|
| This suggests smart pointers in the same design
| could happen be faster. I would be really interested
| when and how.
The intended "suggestion" is that it might not matter to what you're doing,
but it might.
The test file pointainer_speed.cpp does some simple test cases...some show
quite
large releative differences on my compilers, it might be different on others
etc. Maybe
you can get a clue about performance from that test.
Smart pointers could be faster if you wanted to *share* individual objects,
because
you can't really do that with these containers. then again, insome situations,
you could simply do
shared_ptr< ptr_vector<T> > instread of vector< shared_ptr<T> >.
| _____________________________________________________
| 9. docs, Introduction:
|
| "Less flexible than containers of smart pointers"
|
| should have example(s) when.
ok, let me explain that I view the sharing proporty of shared_ptr as a
flexiiblity because
you don't have to worry about lifetime issues. so in that sense these guys are
less flexible.
| _____________________________________________________
| 10. docs, Tutorial:
|
| the first example is extremely long.
|
| There should something primitive and up
| to 1/2 page first. E.g. farm iterators could
| be omitted to keep it small.
|
|
| It would be better to have few small examples
| for each feature than one monster.
ok.
| There should be <ul> list of features
| available in this library and link
| to related example.
|
|
| White space should be minimized in examples.
|
|
| _____________________________________________________
| 11. It should be reconsidered whether to name
| files as "ptr_deque.hpp" or "smart_deque.hpp"
| to reduce number of names user needs to keep
| in head while typing code.
|
| Dtto class names.
ok, I think Pavol should do a vote on that if the library gets accepted.
|
| _____________________________________________________
| 12. docs, example in section "Extending a Sequence":
|
| template< class T >
| struct my_ptr_vector :
| public boost::ptr_sequence_adapter< std::vector<T*> >
|
|
| is the class safe against downcast and then delete?
no. it does not have virtual destructor. I guess that suggest that we should
give
ptr_sequence_adqater and all the others protected cons/de-structor.
| Is it safe to overwrite public functions of parent?
depends on what safe means. there's no virtual functions.
| Should be noted just here before one does cut+paste.
agree.
| _____________________________________________________
| 13. Clonable concept: it is question whether the function
| allocate_clone() shouldn't be named new_clone(),
| being in sync with delete_clone().
|
| Other possibility could be allocate_clone/dellocate_clone.
yes, another candiate for a vote for Pavol.
| _____________________________________________________
| 14 Clonable concept: would it make any sense to provide
| support for placement new/delete also?
I can't answer that question since I have never had the need to use it. I hope
other reviwers can anser it.
| _____________________________________________________
| 15. Clonable concept implementation:
| shouldn't there be try/catch in:
|
| template< class T >
| void delete_clone( const T* t )
| {
| checked_delete( r );
| }
|
| to enforce the constraints?
| At least it would be useful to have it
| in debug mode to report violation.
but then again, shouldn't it then be in checked_delete()? In some sense I feel
it
beyond a library to cope with "fools" :-)
| _____________________________________________________
| 16. Clonable conceptL could there be type traits
| is_clonable() for metaprogramming?
yes, I guess so, and I could use it internally to make a check too.
| _____________________________________________________
| 17. Clonable concept docs: there's link named
| "(see the beginning of <a>Example 9</a>)
| which is unclear. It should point to code.
ok.
| _____________________________________________________
| 18. Clonable concept docs: example how to employ ADL
| and what to do it not present should be added.
| Not every user may be well familiar with the
| technique.
ok.
| _____________________________________________________
| 19. docs aestetics: maybe major sections could
| be separated by <br>.
yes, agree
| _____________________________________________________
| 20. Clonable concept: is there any requirement on
| *a_object == *a_cloned_object?
I guess the requirement could be tightened to say as above iff
there is an operator==(). I'm not sure its useful to say so, so why add it?
| _____________________________________________________
| 21. Clonable concept: is there anything similar to
| std::nothrow?
|
| Something as allocate_clone<std::nothrow>(p);
If people want it there could be. However, we don't want 0 pointers in the
containers, so
what would be the point of it?
| _____________________________________________________
| 22. Clonable concept: would it be possible to add
| support for object factories? Such thing may
| be useful e.g. for COM or CORBA objects.
yes, how do they look like?
| _____________________________________________________
| 23. Clone Manager Concept docs: sentence
|
|
| "second property allows users to apply custom
| allocators/deallocators for the cloned objects"
|
| It should be made clear whether there could be
| one or more custom allocators for cloned objects
| involved in single container instance.
ok, if I understand you correctly, I guess there could be:
1. the allocator used behind the scene in allocate_clone()
2. the allocator use in the underlying container
| _____________________________________________________
| 24. Clone Manager Concept: there are quite a few
| requirements "must not throw".
|
| Shouldn't ther be expressed in terms of T?
| E.g. Throws only if T constructor throw.
not sure why. onthe the destructor says "don't throw" + includes some form of
T. but it is the deallocation
rutine that should not throw, nothing on T .
| _____________________________________________________
| 25. Clone Manager Concept docs: there should be short
| code snippet showing what Clone Manager could
| be used for.
ok.
| _____________________________________________________
| 26. Clone Manager Concept docs: it should be explained
| what is 'view_clone_manager' good for, with
| example, and how it affects pointer ownership.
there is a link to an example...is that a bad example?
| Maybe it should be reconsidered whether it fits
| well within smart container concept.
yes, the reason I have it is because it comes for free given the existing
framework.
| _____________________________________________________
| 27. "The containers are not Assignable"
|
| - Why not? Why not to call clone on asignee pointers
| and delete_clone on the overwritten pointers?
basically because it would be a deviation from the semantics of the underlying
type:
1. Standard containers are copyable and require copyable types
2. smart containers are clonable and require clonable types
consider also that cloning a smart container xan be extreamly expensive...it
deserves
more exposure that a "=".
| _____________________________________________________
| 28. "Ownership can be transferred from a container
| on a per pointer basis".
|
| This should be better explained, with example.
ok, what is missing from the example in the link?
| _____________________________________________________
| 29. docs, Extending Map example:
|
| m1.insert( s, new Foo );
|
| is this exception safe?
yes.
| What if string's
| copy constructor throws?
it is not called. the prototyoe of insert looks like this:
insert( key&, T* )
| _____________________________________________________
| 30. docs, Terminology section, paragraph Ownership:
|
| " smart container or a smart pointer may take
| ownership of an heap-allocated object"
|
|
| "May take" ???
yes, it depends on the clone_manager. if you use the view_clone_manager there
is no ownership.
I should make a footnote.
|
| ".. job to delete that object ..."
|
| ==>
|
| "... responsibility to destroy that object ..."
yes :-)
|
| _____________________________________________________
| 31. review question: "Should we remove rbegin()/rend()?
| Boost.Range makes these unnecessary."
|
|
| No. One may want to use:
|
| #ifdef XYZ
| typedef ptr_vector<AClass> my_vector_t;
| #else
| typedef vector<shared_ptr<AClass> > my_vector_t;
| #endif
|
| and this requires exactly the same interface.
yeah, I think this substitution is wishfull thinking because
1. it give different semantics
2. the interface is not compatible, just consider indirection
however, it might be possible to get
ptr_vector< shared_ptr<T> > vs ptr_vector<T>
but I haven't investigated it in depth before this review determines if there
is a reason to do so.
| _____________________________________________________
| 32. docs, References section: Herb Sutter's site can
| be linked here.
yes, good idea.
| _____________________________________________________
| 33. The mentined "move_ptr" framweorks sounds as
| something what could be standalone Boost library.
yep, Jonathan Turkanis is your friend here.
| _____________________________________________________
| 34. docs, Future directions section:
| it is not clear (to me) what role the
| 'observe()' function has. What idiaom does it support?
ah, yeah, simply that you want to keep a pointer into a collection of
pointers to "observe/change" that value.
| _____________________________________________________
| 35. docs, section "When the stored pointer cannot
| be 0, how do I ...":
|
| - there may be code snippet example.
even though you can see the article at Kevlin's cite?
| _____________________________________________________
| 36. docs, section "Are the pointer containers faster
| and do they have better memory...":
|
| "The short answer is yes: ..."
| ==>
| "Yes: ..."
yes :-)
| _____________________________________________________
| 37. docs, section "What is polymorphic class problem":
|
| - an illustrating example could be here.
yeah, I'll try to think of something. In general it is not hard to see
OO does not feel like a first class experience in C++.
| _____________________________________________________
| 38. docs, section "Why are inserting member function
| overloaded for both pointers and references?
| REVIEW QUESTION: do we want this behavior?"
|
| - IMO no. Very confusing.
ok, noted. there is one motivation for map/set: here we can check if the
object already
exists and hence avoid a cloning in those cases. could be a big imrpovement.
It will also make it slightly
easier to go from
vector<string> to ptr_vector<string> and vice versa
if it would make sense.
|
| _____________________________________________________
| 39. docs question: "Which mutating algorithms are safe
| to use with pointers?"
|
|
| Maybe overloads of std::unique etc could be added
| to avoid accidental misuse. Something like:
|
| namespace std {
|
| template<...>
| xyz unique(boost::ptr_vector<T>::iterator, ...);
|
| }
|
| At least there should be exhaustive list of
| nnt-supported std and Boost algorithms.
ok. the above is not possible since we cannot do partial sepcialization of
function templates.
| _____________________________________________________
| 41. review question 6: (about using Range): why not both?
the iterator version can be emulated by make_iterator_range( ... );
but hey, I don't mind both
| _____________________________________________________
| 42. review question 8: (const_begin/const_end): no.
| Have an example with Range for what is useful.
ok.
| _____________________________________________________
| 43. review question 9: (key iterator): why is such
| thing needed for? map::iterator->first isn't enough?
you have to use transform_iterator or manually code a loop to do something as
simple as
the copy() operation. I find that I have wanted it a couple of times, and that
the other alternatives
are daoable, but irritating.
| _____________________________________________________
| 44. review question 11: rather no, feels as
| hole into type system.
ok.
| _____________________________________________________
| 45. Will there be support for circular_buffer library
| at some time?
at the circular buffer review I explicitly asked for exception-safety
guarantees of the buffer to
enable it to become a smart container, however, I assume the is less need for
it compared to
a value_based interface. I think ptr_deque<> will make for quite fast queues
in this domain.
If there is a genuine need, it would be relatively easy to add, me think.
| I would ask for Multi Index but don't know enough
| to judge its feasibility.
yeah, let's get this baby accepted first. The view_clona_manager do provide
some means on which it is faily
easy to get different interfaces.
| _____________________________________________________
| 46. docs, "Library headers" section: the heareds should
| be hyperlinked for convenience.
ok.
| _____________________________________________________
| 47. There should be <boost/smart_containers.hpp>
| (note its location and plural at the end).
|
| Also <boost/smart_containers_fwd.hpp> should exist.
yeah, maybe. there is really several ways we can make traits in. for example
struct X
{
typedef int x_type;
};
will allow us to identify X without including any header.
| _____________________________________________________
| 48. What is boost/smart_container/template.hpp for?
for me when I made a new header.
| And boost/smart_container/detail/undef.hpp?
to be scrapped.
| _____________________________________________________
| 49. clone_manager.hpp should have
|
| #if defined(_MSC_VER) && (_MSC_VER >= 1200)
| # pragma once
| #endif
|
|
| Similarly move_ptr headers and maybe others.
yes
| _____________________________________________________
| 50. The directory with headers should use plural:
| boost/smart_containers. It is in sync with library name.
ok.
|
| _____________________________________________________
| 51. boost/smart_container/detail/size_undoer.hpp:
| shouldn't ScopeGuard be used instead of this?
|
| There's copy of Alexandrescu's implementation
| within MultiIndex library.
I guess it could. Currently I have removed the resize() functions from the
vector interface so it would not be needed.
| _____________________________________________________
| 52. The library should not use sub-namespace detail
| but smart_pointers_detail or so to avoid
| possible clashes.
yes.
| _____________________________________________________
| 53. exception.hpp: the function argument should
| not be named 'what' as it is confusing with what()
| function.
really? the intention is that is what you get from what(). but I don't mind
something else.
| _____________________________________________________
| 54. ptr_array.hpp: typo in:
|
| throw bad_index( "'replace()' aout of bounds" );
thanks!
| _____________________________________________________
| 55. exception.hpp: the names bad_smart_container_operation,
| bad_index and bad_pointer are too generic,
| polluting namespace and and non-descriptive.
|
| They should be changed to:
| - smart_containers_exception_base
| - smart_containers_invalid_index_value
| - smart_containers_null_pointer_inserted
ok, Pavol should make a vote about this.
|
| These exceptions should be declared in
| <boost/smart_containers_fwd.hpp>.
what for?
| _____________________________________________________
| 56. There should be ptr_slist.hpp and
| maybe ptr_hash_XYZ variant.
|
| Support for future boost::unordered_map/set
| could be added too.
yeah, I'm waiting for a boost implementation of them to appear.
| _____________________________________________________
| 57. Maybe boost::tuple could be supported as well.
too far away in my opinion.
| _____________________________________________________
| 58. The documentation could contain result of
| a bechmark, how faster is access via ptr_vector
| copmpared to vector<shared_ptr> for example.
yes, agree.
| _____________________________________________________
| 59. clone_manager.hpp: in delete clone BOOST_ASSERT
| could be added:
|
| template< class T >
| void delete_clone( const T* r )
| {
| BOOST_ASSERT(r);
| checked_delete( r );
| }
|
| There are for sure many other places.
yeah, perhaps.
| _____________________________________________________
| 60. source code refers to old name of the library
| in comments:
|
| /**
| * Pointer-Container Library
|
| _____________________________________________________
| 61. Source should be cleaned up from remnants like:
|
| //#undef BOOST_FORWARD_TYPEDEF
| //#undef BOOST_SMART_CONTAINER_RELEASE_AND_CLONE
|
| in ptr_list.hpp.
yes.
| _____________________________________________________
| 62.ptr_list.hpp:
|
| template< typename T, typename A >
| inline ptr_list<T,A>* allocate_clone( const ptr_list<T,A>& r )
| {
| return r.clone().release();
| }
|
|
| could clone() fail and return 0? What if there's
| special allocator returning 0 instead of throwing?
that is not allowed in the clonable concept. I should make this more explicit
in that concept.
| _____________________________________________________
| 63. The source code surely won't suffer from having
| some overview sections. Like what is this file
| for, what are related files to look on etc.
it probably won't...
| _____________________________________________________
| 64. documentation should have section how to
| 'smartify' an user container, preferably with step
| by step example.
yea, agree.
|
| _____________________________________________________
| 65. details/scoped_deleter.hpp: there seems no need
| for scoped_array here (only to bloat executable
| and slower compilation).
hm...I need to manage a resource and I prefer not to do so manually.
I canøt imagine that scoped_array<> afffects the executable at all.
| _____________________________________________________
| 66. detail/reversible_smart_container.hpp, line 373:
|
| else
| ;
| }
|
|
| ????
else nothing. just as it is documented in the standard. But I have not
included resize so this code is to be deleted.
| _____________________________________________________
| 67. It would be nice to support systems without
| enabled exceptions (BOOST_NO_EXCEPTIONS).
this is harder than it seems because I would have to check return values for
0, right?
| _____________________________________________________
| 65. details/scoped_deleter.hpp: member released_
| can be eliminated, Negative value of stored_ could
| have its function.
|
| IMHO more attention could be taken on
| possible optimoizations here as this class
| feels to be on performance critical path.
|
|
| Maybe the dynamically allocated array could
| be optimized away when size == 1.
|
| Also to avoid code bloat the generic void*
| implementation could be used as core.
yeah, I disagree, but It is really hard to do optimzations without data to
back that up.
So I'll better wait till that data exists. Moreover, the big time consumer is
heap-allocations, not
much else.
| _____________________________________________________
| 66. there's file with funny name map_iterator_old.hpp.
to be deleted.
|
| _____________________________________________________
| 67. detail/map_iterators.hpp: the extremely hard to read
| lines like:
|
| template< typename I, typename K, typename V > // I = original iterator, K
| = key type, V = return value type of operator*()
| class map_iterator : bidirectional_iterator_helper< map_iterator<I,K,V>,
| std::pair<K,V>, // V*?
| std::ptrdiff_t,
| std::pair<K,V>*, // V*?
| V& >
|
|
| Must be rearranged.
ok.
| _____________________________________________________
| 68.
|
| Likewise in ptr_map_adapter.hpp:
|
| typedef BOOST_DEDUCED_TYPENAME
| smart_container::detail::map_iterator<
| BOOST_DEDUCED_TYPENAME Map::const_reverse_iterator,
| BOOST_DEDUCED_TYPENAME Map::key_type,
| const value_type>
| const_reverse_iterator;
|
|
| I have problem
| to find what
| is end and what
| is beginning here
what do you suggest?
|
| _____________________________________________________
| 69. ptr_map_adapter.hpp:
| shouldn't operator[] be unsafe, check nothing
| fast operation and at() the safe one?
|
| Right now they both default to the same call
| lookup(). This is againts STL habits.
|
| IMHO BOOST_ASSERT + potetially unsafe operator[]
| should be used.
yeah, but this is a map, not a vector. There are several choices here, eg,
call at() lookup() etc.
|
| _____________________________________________________
| 69. ptr_map_adapter.hpp: should have
| #include <memory>
|
| because of using std::auto_ptr.
already in reversible_smart_container.hpp
|
| _____________________________________________________
| 70. ptr_map_adapter.hpp: file ends with funny
|
| #endif
fixed.
| _____________________________________________________
| 72. ptr_predicate.hpp:
|
| #if defined(_MSC_VER) && (_MSC_VER >= 1200)
| #pragma once
| #endif
|
|
| should be realigned for aesthetic reasons.
ok.
| _____________________________________________________
| 72. ptr_predicate.hpp: maybe name
| "pointed_equal_to" is better than
| "ptr_equal_to".
yeah, this is related to issue 4. I think one class like indirected<predicate>
might be the way to go...it would
replace this entire header.
|
| _____________________________________________________
| 73. ptr_predicate.hpp: the functors could have:
|
| struct XYZ {
| #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
| char dummy_; // BCB would by default use 8 bytes for empty class
| #endif
| ....
| };
|
| optimization for BCB. There's no way to
| make it smaller with this compiler and no easier.
yes.
| _____________________________________________________
| 74. ptr_set.hpp: the code as:
|
| template< class Key, class Compare = ptr_less<Key>,
| class CloneManager = heap_clone_manager >
| class ptr_set :
|
| could be rearranged into readable form:
|
|
| template
| <
| class Key,
| class Compare = ptr_less<Key>,
| class CloneManager = heap_clone_manager
| >
| class ptr_set :
yeah, not too bad.
|
| _____________________________________________________
| 75. There could be some static asserts to avoid one
| trying ptr_vector<int>.
why forbid it? it might be usefull together with the view_clone_manager
| _____________________________________________________
| 76. Why there is no swap() between smart containers?
|
| Futhermore one may want operators ==, !=, <, ...
there is. boost.operators take care of that.
| _____________________________________________________
| 77. detail/associative_smart_container.hpp:
| why is there the "this" in:
|
| this->remove( i );
|
| and so like?
to find remove() during two-phase lookup. this is required by the standard
| _____________________________________________________
| 78. will ptr_list<...>::sort() work?
yes, eventually. it's related to the algorithm issue.
| _____________________________________________________
| 79. In debug more there could be check that
| inserted pointer is really unique.
yes.
| _____________________________________________________
| 80. Function
|
| template<class Container, class T, class SmartContainer>
| Container<shared_ptr<T> >
| boost::convert(SmartContainer<T>& cont);
|
| may come useful sometimes.
|
| ptr_list<X> cont1;
|
| vector<shared_ptr<X> > cont2 =
| convert<vector>(cont1);
|
| E.g. for "legacy" (= pre-smart container) libraries.
ok.
Thanks for your review. Hair-raising as ususal :-)
-Thorsten
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk