
Matt Calabrese wrote:
On 7/3/06, Thorsten Ottosen <thorsten.ottosen@dezide.com> wrote:
As long as C++ does not have move-semantics, the semantics of clone_ptr seems to be far too expensive to be useful: std::vector<clone_ptr<T>> will have to re-clone all objects on buffer expansion, whereas boost::ptr_vector<T> will not.
Firstly, while it is true that it may be expensive to copy such objects for some users, it certainly isn't "far too expensive" for all users, as many programmers likely are simply not bound by the copy operations of the types they may be using with it -- an assumption either way made at the library level, in my opinion, is a mistake in design.
Well, we usually prefer "as efficient as possible" for libraries.
If value semantics are desired for a given type, a programmer shouldn't have to jump through hoops using a type with reference semantics and explicit cloning in order to get the functionality they want -- this is refering to the types in general, not just with respect to them being stored inside of containers.
If value semantics are desired, then why not provide them directly? Having polymorphic types with value semantics is fairly rare.
But the big point here is that, apart from all of this, even without move semantics in the language, efficient containment can be accomplished very easily in the form of compliant STL containers, and I'd argue that it can be done in a simpler and more intuitive manner than what is provided by the current pointer containers and even be exactly as efficient! This can be done by just creating the clone_ptr template and then partially specializing the standard STL containers rather than working with ptr_container containers, as is explicitly allowable per 17.4.3.1 paragraph 1 of the standard. Specializations would be fully compliant to the standard, while also providing many of the ptr_container optimized operations on top of the standard operations.
It is a lot more work to write an efficient/correct standard container library, than to write the pointer container library on top of the standard library. So I don't agree with "simpler" here.
The benefit of this is that the user of the library is really only introduced to one new template, the clone_ptr template, and they can use that type with any STL container they wish, even with ::std::vector, and the implementation may avoid unecessary copies just like ptr_vector. The user doesn't even have to be aware of the additional member functions unless they need such functionality.
This is not a benefit. std::vector is designed for value semantics, boost::ptr_vector for polymorphic semantics. neither can easily replace the other.
This also has several other benefits over the current ptr_containers, particularly with respect to writing generic code, as instantiating a vector of clone_ptrs can be done exactly as you would a vector of other types, making the optimization entirely transparent to the writer of the generic code. For instance, imagine a type template whose instantiations encapsulate an ::std::vector of a type which is specified through an argument of the encapsulating template. As an example:
template< typename Type > struct some_type { ::std::vector< Type > container; };
Now, imagine that someone instantiating the template wishes to have the internal container contain "animals," where animal is an abstract base class and the user would be storing dynamic instances of cats, dogs, etc. which are derived from the animal type. This could be desired for some of the same reasons you may wish to have a container of variants, but with the restriction of used types being those which are any possible children of a specified type rather than types which must be individually explicitly specified when instantiating a variant. With the clone_ptr concept and the associated specializations, the person would merely instantiate the encapsulating some_type template with clone_ptr< animal >, and internally the optimized vector implementation would be used automatically without any explicit intervention on the part of the person using the template nor the person writing the template.
Without a clone pointer type of concept, it is much more difficult to make the code both generic and efficient.
Depends on your definition of efficient.
optimizations remain as implementation details rather than separate containers and any code already written does not have to be changed in order to take advantage of the optimizations.
If you think you doing programmers a favor by muddling the distinction between value semantics and polymorphic semantics, I think you're wrong. -Thorsten