
On 7/09/06, Matt Calabrese <rivorus@gmail.com> wrote:
As we established, the types being created aren't really smart pointers but are actually smart objects.
If that is true, then is the following form really correct?: clone_ptr<Base> p(new Derived); Wouldn't it be more-correct to write: Derived d; clone_ptr<Base> p(d); On 7/10/06, Matt Calabrese <rivorus@gmail.com> wrote:
On 7/9/06, Kevin Spinar <spinarkm@gmail.com> wrote:
First, let me make an assumption. Most people who would use clone_ptr<T> would have T be an abstract base class with no member variables. Now, how would someone write a sorting predicate with that? Double dispatch is a solution, but probably not a desirable solution. Or is my assumption incorrect?
Right, for most uses it would be difficult to implement. Still, as tough as it is, comparing the pointer value simply isn't correct, so I wouldn't even consider that an option at all. If you agree, then the only options I can think of are either some form of forwarded operation, or no definition at all. It's true that neither one seems great, so maybe there is a better solution out there, but I personally don't see it. The only reason I am leaning towards some form of forwarded solution is that in the case that comparison operators actually are implemented, it allows the user to work with sorted containers and algorithms without having the explicitly specify a comparison predicate. To be honest, I don't mind either way as I personally don't have much of a need for the comparison functionality.
Ok, perhaps comparison forwarding would be the best solution.
Another alternative would be to throw an exception upon using * or -> on a default-constructed clone_ptr, though that would add yet more overhead to those operators.
True, and I personally do not enjoy working with operations that can potentially throw or dereference null pointers, especially with such seemingly simple and common operations. Writing code is much easier when errors and exceptions are avoided entirely by design if possible.
I suppose the best solution would be what you suggested earlier: "perhaps a default child type were specified via a template argument to the smart object type template itself (which would default to the first type if left unspecified)." On 7/10/06, Peter Dimov <pdimov@mmltd.net> wrote:
clone_ptr (or copy_ptr, or copy_on_write_ptr) is a better name from a "marketing standpoint" than poly_obj, because it's more recognizable.
Opinions? Accurate name or recognizable name?
Regarding:
template<class Y, class Alloc> clone_ptr(Y * p, Alloc); // Y must be complete
The template parameter name 'Alloc' implies a standard allocator. This is pretty confusing; you should rename it to CloneAlloc if you really want to use the 'CloneAllocator concept'.
Indeed and I'll admit there is other naming and documentation issues I should address before releasing this.
The alternative is to just take a standard allocator.
The reasoning to have a a clone allocator concept ( http://www.boost.org/libs/ptr_container/doc/reference.html#the-clone-allocat... ) is to allow for cloning of objects which don't have public copy constructors or to allow people to do something other than copy construct.
You might also want to not ignore the actual argument and make an effort to support stateful allocators (although this is somewhat more complicated, it is also considerably more useful.)
I agree. ptr_container's clone allocators don't seem to be meant for keeping stateful allocators (their functions are static). Perhaps it's time to break away from ptr_container's clone allocator and have my own clone allocator concept.
The copy on write semantics are problematic from an usability standpoint. Consider this code:
// thread 1
int x1 = p->x;
// thread 2
int x2 = p->x;
Is this legal (assuming that both threads use the same pointer p)? You can't tell without looking at p. If it's const, or points at const, the code is legal. The problem is that there are no visible mutating operations in the code; it looks innocent enough as all we do is read p->x, right?
I intended to add mutexes and thread safety to the code. Is there more to this issue than that? Though I suppose adding locks to a getter function isn't that desireable efficiency-wise.
One option is to always return a const from -> and * and provide a separate mutable accessor.
Not exactly the most desirable solution, but it seems many things in this aren't turning out as I originally expected. Of course, if we go back to clone-on-copy semantics, this won't be an issue. Kevin Spinar