Topic: Recommend adding clone and COW smart pointers to the standard


Author: Axter <google@axter.com>
Date: Thu, 6 Oct 2005 22:18:54 CST
Raw View
Shezan Baig wrote:
> Axter wrote:
> > Shezan Baig wrote:
> > > Yes, but the behaviour of the class, as a whole, is value semantic -
> > > not reference semantic (e.g., when you do 'operator=', you're actually
> >
> > IMHO, this would be like expecting an auto_ptr not to call the
> > destructor, because it's suppose to be emulating a pointer, and
> > pointers don't automatically delete themselves.
>
>
> That is not the point.  The point is pointers have reference semantics,
> but the proposed 'copy_ptr' has value semantics.

My point is that I believe it's a big mistake to have smart pointers
that use poitner semantics for their operators.
It's far more pratical and far more useful for smart pointers to
evaulate what they're pointing to, instead of the pointer address.


> > And it would be more practical if (ptr1 == ptr2) is actually comparing
> > the objects being pointed to, instead of the address of the pointers.
>
>
> This is precisely because pointers have reference semantics.  When you
> compare pointers, you want to see whether they *refer* to the same
> object.

I don't want see that.
I don't see the pratical use of having smart pointer compare their
address.  I'm sure their are some requirements for this, but for smart
pointer it's far more common to have a requirement to check for object
comparison instead of pointer address comparison.

>>You're checking the identity of the object, not the value of
> the object.  If you want to compare values, then don't use a pointer.

First rule I teach to all newbies, is don't use pointers unless you
have to.
So if you're using a pointer, it's because you have to use the pointer.

And when you have such pointer requirements, you should be able to use
a smart pointer that is smart enough to know that you want object
comparison and not pointer address comparison.
And IMHO, such a smart pointer should be added to the standard.
Moreover, IMHO, the shared_ptr should have object value comparison
instead of pointer address comparison.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Axter" <google@axter.com>
Date: Fri, 30 Sep 2005 23:41:34 CST
Raw View
Currently, the C++ standard has no practical methods of implementing a
container of abstract pointers in which you can copy the object values
from one container to another, or from one section of the container to
another.

I like to see clone smart pointers and COW (Copy On Write) smart
pointers be added to the standard.
See following classes:
http://code.axter.com/copy_ptr.h  (Clone Smart Pointer)
http://code.axter.com/cow_ptr.h  (COW Smart Pointer)

The above clone & COW pointers can be used to create an STL container
of abstract pointers, and can copy the derived object from one
container to the next.
Example

vector<copy_ptr<Base> > vBase1;
vBase1.push_back(new Derived);
//The following will create another copy of Derived, and not a copy of
the pointer
vBase1.push_back(vBase1[0]);

vector<copy_ptr<Base> > vBase2;
vBase2 = vBase1; //vBase2 gets a copy of the Derived object, and not a
copy of the pointer

std::auto_ptr and boost::shared_ptr, can not accomplish the above
logic, because it copies the pointer, and not the object itself.

Both copy_ptr and cow_ptr are more generic then other similar classes
since they don't require the Base class to have a clone method.
See following link for more example code.
http://www.codeguru.com/Cpp/Cpp/algorithms/general/article.php/c10407/

The above link is a little out dated, and it uses clone_ptr smart
pointer, which has a method that is not as efficient as the copy_ptr
and cow_ptr implementation.  But it presents the general benefits along
with potential shortfalls.

I see this required logic asked for frequently in newsgroups and in web
based forums.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Shezan Baig" <shezanbaig2004@gmail.com>
Date: Sat, 1 Oct 2005 12:03:55 CST
Raw View
Axter wrote:
> Currently, the C++ standard has no practical methods of implementing a
> container of abstract pointers in which you can copy the object values
> from one container to another, or from one section of the container to
> another.
>
> I like to see clone smart pointers and COW (Copy On Write) smart
> pointers be added to the standard.
> See following classes:
> http://code.axter.com/copy_ptr.h  (Clone Smart Pointer)
> http://code.axter.com/cow_ptr.h  (COW Smart Pointer)


Regarding the Clone Smart Pointer - I like the intent and there are
definitely many use cases, but in terms of implementation - I wouldn't
call it a pointer but some kind of "variant".  What I mean is that,
since you are trying to emulate value semantics, it should behave like
a value semantic class.

For consistency, I would remove 'operator->' and 'operator*' and
replace them with a 'get_object' function (to prevent it looking like a
pointer when used by clients).

I also find the arithmetic and comparison operators a little
disturbing, since they operate on the sliced abstract objects, and not
the actual derived objects.  I would take them out altogether.

The equality operators could stay though, since all well-behaved value
semantic classes should have equality operators (hopefully! :D).  And,
they shouldn't operate on the sliced base objects, you will need to
access the most derived objects using some virtual interface.
Obviously, if the most derived objects are not of the same type (use
RTTI to determine), then they should just evaluate to not equal.

-shez-

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Shezan Baig" <shezanbaig2004@gmail.com>
Date: Sun, 2 Oct 2005 11:09:10 CST
Raw View
Axter wrote:
> Currently, the C++ standard has no practical methods of implementing a
> container of abstract pointers in which you can copy the object values
> from one container to another, or from one section of the container to
> another.
>
> I like to see clone smart pointers and COW (Copy On Write) smart
> pointers be added to the standard.
> See following classes:
> http://code.axter.com/copy_ptr.h  (Clone Smart Pointer)
> http://code.axter.com/cow_ptr.h  (COW Smart Pointer)


Regarding the COW Smart Pointer, again the intent is good, but there
are problems with the interface/implementation.  Since the 'get_ptr'
function is overloaded based on const-ness, the following code will
give me unexpected behaviour:

copy_ptr<SomeObject> a = // ...
copy_ptr<SomeObject> b = a;  // should share object

// when you call b.get_ptr(), then a and b don't share objects and
// assertion will fail
assert(a.get_ptr() == b.get_ptr());

This behaviour changes completely if 'b' is declared const.  IMO, it is
not a good thing for objects to change behaviour so drastically based
on const-ness.

I would suggest 'get_ptr' always return const pointer, and you add
another function 'modify_object' that returns a non-const pointer.
That way, the user makes their intent clear whether they want to modify
the object or just access it.

Regarding the arithmetic & comparison operators, I wasn't thinking in
my previous post when I wrote that the objects get sliced - obviously I
was wrong.  But in order for them to behave as expected, the operators
in the base class would need to be declared virtual and do the
appropriate down-cast (ugly, IMO) in the derived class.  So I would
still suggest to remove them and make the user explicitly dereference
the cow_ptr to run the operators.

-shez-

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Axter" <google@axter.com>
Date: Mon, 3 Oct 2005 12:55:21 CST
Raw View
Shezan Baig wrote:
> Axter wrote:
> > Currently, the C++ standard has no practical methods of implementing a
> > container of abstract pointers in which you can copy the object values
> > from one container to another, or from one section of the container to
> > another.
> >
> > I like to see clone smart pointers and COW (Copy On Write) smart
> > pointers be added to the standard.
> > See following classes:
> > http://code.axter.com/copy_ptr.h  (Clone Smart Pointer)
> > http://code.axter.com/cow_ptr.h  (COW Smart Pointer)
>
>
> Regarding the Clone Smart Pointer - I like the intent and there are
> definitely many use cases, but in terms of implementation - I wouldn't
> call it a pointer but some kind of "variant".  What I mean is that,
> since you are trying to emulate value semantics, it should behave like
> a value semantic class.

I agree, but since we can not overload operator.(), (IMHO) the next
best thing is to use operator->().
And since this smart pointer is specifically designed for use with
abstract pointers, I think it would be confusing trying to use
reference syntax with an abstract pointer.

IMHO, smart pointers should have never been made to completely emulate
a pointer, and instead should have had dereference logic in their
operators.


> I also find the arithmetic and comparison operators a little
> disturbing, since they operate on the sliced abstract objects, and not
> the actual derived objects.  I would take them out altogether.

As you correctly pointed out in your follow-up post, the arithmetic and
comparison operators can work on the derived type, and not get sliced.

I can see dropping the arithmetic operators, but the comparison
operators are required logic for the goals of this class.
One of the main goals of the class, is to make a clone smart pointer
that can be used with all the main STL library containers.
If the comparison operators where removed, it would be difficult to use
the smart pointer in an associated STL container with desired
functionality.

std::map<copy_ptr<abstract_foo>, int> mFoo;
The above line of code needs clone pointer comparison operator for
desired functionality.
Also the following code......
std::list<copy_ptr<abstract_foo> > lstFoo;
lstFoo.sort();

It's difficult to use a smart pointer like boost::shared_ptr, in the
above code logic, because it's trying to apply strict pointer
emulation.
IMHO, (strict pointer emulation), makes the smart pointer less
practical and less functional.

That's why I believe the clone and the COW (Copy On Write) smart
pointers should not follow this paradigm, and instead should use an
interface that is more functional instead of more consistent.

Thanks for the feedback

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: sparent@adobe.com (Sean Parent)
Date: Tue, 4 Oct 2005 03:56:38 GMT
Raw View
The limitation of not being able to override operator.() does not, in my
opinion, justify confusing value and pointer semantics. See
<http://opensource.adobe.com/classadobe_1_1copy__on__write.html> for an
alternative copy_on_write implementation - I've strived for simplicity for
this implementation (it's the 4th production attempt I've made at trying to
get a good COW implementation).

For the copy_ptr - I would rather see something along the lines of
boost::any - which can be parameterized with an interface. I'm working on
such a library that I hope to have ready in time for C++ Connections (my
talk is about problems with using object oriented programming techniques
with Concept based programming).

Sean


in article 1128347694.784966.258180@f14g2000cwb.googlegroups.com, Axter at
google@axter.com wrote on 10/3/05 11:55 AM:

> Shezan Baig wrote:
>> Axter wrote:
>>> Currently, the C++ standard has no practical methods of implementing a
>>> container of abstract pointers in which you can copy the object values
>>> from one container to another, or from one section of the container to
>>> another.
>>>
>>> I like to see clone smart pointers and COW (Copy On Write) smart
>>> pointers be added to the standard.
>>> See following classes:
>>> http://code.axter.com/copy_ptr.h  (Clone Smart Pointer)
>>> http://code.axter.com/cow_ptr.h  (COW Smart Pointer)
>>
>>
>> Regarding the Clone Smart Pointer - I like the intent and there are
>> definitely many use cases, but in terms of implementation - I wouldn't
>> call it a pointer but some kind of "variant".  What I mean is that,
>> since you are trying to emulate value semantics, it should behave like
>> a value semantic class.
>
> I agree, but since we can not overload operator.(), (IMHO) the next
> best thing is to use operator->().
> And since this smart pointer is specifically designed for use with
> abstract pointers, I think it would be confusing trying to use
> reference syntax with an abstract pointer.
>
> IMHO, smart pointers should have never been made to completely emulate
> a pointer, and instead should have had dereference logic in their
> operators.
>
>
>> I also find the arithmetic and comparison operators a little
>> disturbing, since they operate on the sliced abstract objects, and not
>> the actual derived objects.  I would take them out altogether.
>
> As you correctly pointed out in your follow-up post, the arithmetic and
> comparison operators can work on the derived type, and not get sliced.
>
> I can see dropping the arithmetic operators, but the comparison
> operators are required logic for the goals of this class.
> One of the main goals of the class, is to make a clone smart pointer
> that can be used with all the main STL library containers.
> If the comparison operators where removed, it would be difficult to use
> the smart pointer in an associated STL container with desired
> functionality.
>
> std::map<copy_ptr<abstract_foo>, int> mFoo;
> The above line of code needs clone pointer comparison operator for
> desired functionality.
> Also the following code......
> std::list<copy_ptr<abstract_foo> > lstFoo;
> lstFoo.sort();
>
> It's difficult to use a smart pointer like boost::shared_ptr, in the
> above code logic, because it's trying to apply strict pointer
> emulation.
> IMHO, (strict pointer emulation), makes the smart pointer less
> practical and less functional.
>
> That's why I believe the clone and the COW (Copy On Write) smart
> pointers should not follow this paradigm, and instead should use an
> interface that is more functional instead of more consistent.
>
> Thanks for the feedback
>
> ---
> [ comp.std.c++ is moderated.  To submit articles, try just posting with ]
> [ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
> [              --- Please see the FAQ before posting. ---               ]
> [ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]
>

--
Sean Parent
Sr. Computer Scientist II
Advanced Technology Group
Adobe Systems Incorporated
sparent@adobe.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Shezan Baig" <shezanbaig2004@gmail.com>
Date: 4 Oct 2005 04:00:05 GMT
Raw View
Shezan Baig wrote:
> copy_ptr<SomeObject> a = // ...
> copy_ptr<SomeObject> b = a;  // should share object


This should be 'cow_ptr<SomeObject>', of course :)

-shez-

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Shezan Baig" <shezanbaig2004@gmail.com>
Date: 4 Oct 2005 04:00:29 GMT
Raw View
Axter wrote:
> I agree, but since we can not overload operator.(), (IMHO) the next
> best thing is to use operator->().
> And since this smart pointer is specifically designed for use with
> abstract pointers, I think it would be confusing trying to use
> reference syntax with an abstract pointer.


Yes, but the behaviour of the class, as a whole, is value semantic -
not reference semantic (e.g., when you do 'operator=', you're actually
assigning the *value* of the object, and not what the object *refers*
to).  When I see 'operator->' and 'operator*', it immediately puts my
mind in reference semantic mode (think pointers, iterators etc).  This
is what I meant by confusing - that's why I prefer an explicit
'get_object' method (for lack of a better name).

It might be a subjective thing - if everything in your world is value
semantic, it probably doesn't make any difference.

-shez-

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Shezan Baig" <shezanbaig2004@gmail.com>
Date: 4 Oct 2005 04:00:33 GMT
Raw View
Axter wrote:
> std::map<copy_ptr<abstract_foo>, int> mFoo;
> The above line of code needs clone pointer comparison operator for
> desired functionality.
> Also the following code......
> std::list<copy_ptr<abstract_foo> > lstFoo;
> lstFoo.sort();


Do you have a proposal of how to handle cases when the list contains
objects of different types?


class abstract_foo { ... };
class derived1 : public abstract_foo { ... };
class derived2 : public abstract_foo { ... };

std::list<copy_ptr<abstract_foo> > lstFoo;
lstFoo.push_back(new derived1(...));
lstFoo.push_back(new derived2(...));
lstFoo.sort();


What should be the behaviour?  It seems like we are losing type safety
in this approach.

-shez-

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Axter" <google@axter.com>
Date: Tue, 4 Oct 2005 23:28:48 CST
Raw View
Shezan Baig wrote:
> Axter wrote:
> > I agree, but since we can not overload operator.(), (IMHO) the next
> > best thing is to use operator->().
> > And since this smart pointer is specifically designed for use with
> > abstract pointers, I think it would be confusing trying to use
> > reference syntax with an abstract pointer.
>
>
> Yes, but the behaviour of the class, as a whole, is value semantic -
> not reference semantic (e.g., when you do 'operator=', you're actually
> assigning the *value* of the object, and not what the object *refers*
> to).  When I see 'operator->' and 'operator*', it immediately puts my
> mind in reference semantic mode (think pointers, iterators etc).  This
> is what I meant by confusing - that's why I prefer an explicit
> 'get_object' method (for lack of a better name).


IMHO, this would be like expecting an auto_ptr not to call the
destructor, because it's suppose to be emulating a pointer, and
pointers don't automatically delete themselves.

IMHO, a smart pointer should really be just that.  It should be smart,
and that should include logic that is smart enough to know that you
want to compare what your object is pointing to, and not the actual
address.

I don't see the practical use of having a smart pointer's operators
work on the pointer address.
I think if that type of comparison needs to be made, it should be
reserved for special functions (ptr1.get_ptr() == ptr2.get_ptr())
And it would be more practical if (ptr1 == ptr2) is actually comparing
the objects being pointed to, instead of the address of the pointers.

Why have a smart pointer that is only semi smart?

Doing something for the sake of consistency, is only good if it's
consistently good or consistently neutral.
IMHO, dumb (raw) pointer operator logic is consistently bad, in that
it's confusing and easy to get wrong for new developers.  It's also
bad, because it makes it harder to use pointers in associated
containers and it makes it more difficult to sort containers of
pointers.
I don't think this type of consistency should be added to smart
pointers.  IMHO, it would be consistently bad.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Axter" <google@axter.com>
Date: Tue, 4 Oct 2005 23:28:56 CST
Raw View
Shezan Baig wrote:
> Axter wrote:
> > std::map<copy_ptr<abstract_foo>, int> mFoo;
> > The above line of code needs clone pointer comparison operator for
> > desired functionality.
> > Also the following code......
> > std::list<copy_ptr<abstract_foo> > lstFoo;
> > lstFoo.sort();
>
>
> Do you have a proposal of how to handle cases when the list contains
> objects of different types?
>
>
> class abstract_foo { ... };
> class derived1 : public abstract_foo { ... };
> class derived2 : public abstract_foo { ... };
>
> std::list<copy_ptr<abstract_foo> > lstFoo;
> lstFoo.push_back(new derived1(...));
> lstFoo.push_back(new derived2(...));
> lstFoo.sort();
>
>
> What should be the behaviour?  It seems like we are losing type safety
> in this approach.

How different derived types are handle is determined by the developer
and the required designed.
For example, let say you have a class called shape, and you want to
sort your shape in the order of square area.
Each derived class would determine the logic for its square area.
That is not something you want to put in your base class.
This would not loose type safety, any more then using virtual functions
can lead to losing type safety.

If you think in abstract terms, you can easily determine what the code
would look using the clone smart pointer operators.

The following example code illustrates how easy it is to use the
copy_ptr clone smart pointer in a container.
The logic below would be difficult to produce using boost::shared_ptr
or other similar smart pointers.
Example code:

const double pi = 3.14f;

class shape
{
public:
 virtual int SquareArea()const=0;
 bool operator<(const shape& s)const{return (SquareArea() <
s.SquareArea());}
 virtual ~shape(){}
};

class rectangle : public shape
{
public:
 rectangle(int x, int y):m_x(x), m_y(y){}
 rectangle(const rectangle &src):m_x(src.m_x), m_y(src.m_y){}
 int SquareArea()const{return m_x * m_y;}
private:
 int m_x;
 int m_y;
};
class circle : public shape
{
public:
 circle(double radius_):m_radius(radius_){}
 circle(const circle &src):m_radius(src.m_radius){}
 int SquareArea()const{return (int)(pi * m_radius * 2);}
private:
 double m_radius;
};




int main(int argc, char**)
{
 std::list<copy_ptr<shape> > vShape1;
 vShape1.push_back(new rectangle(12, 23));
 vShape1.push_back(new circle(65));
 vShape1.push_back(new circle(38));
 vShape1.push_back(new rectangle(29, 11));
 std::list<copy_ptr<shape> > vShape2(vShape1);
 vShape2.sort();
 for(std::list<copy_ptr<shape> >::iterator i1 = vShape1.begin();i1 !=
vShape1.end();++i1)
 {
  std::cout << (*i1)->SquareArea() << std::endl;
 }

 std::cout << std::endl << std::endl;

 for(std::list<copy_ptr<shape> >::iterator i2 = vShape2.begin();i2 !=
vShape2.end();++i2)
 {
  std::cout << (*i2)->SquareArea() << std::endl;
 }

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Shezan Baig" <shezanbaig2004@gmail.com>
Date: Thu, 6 Oct 2005 00:03:42 CST
Raw View
Axter wrote:
> Shezan Baig wrote:
> > Yes, but the behaviour of the class, as a whole, is value semantic -
> > not reference semantic (e.g., when you do 'operator=', you're actually
>
> IMHO, this would be like expecting an auto_ptr not to call the
> destructor, because it's suppose to be emulating a pointer, and
> pointers don't automatically delete themselves.


That is not the point.  The point is pointers have reference semantics,
but the proposed 'copy_ptr' has value semantics.  Most smart pointers
have their own destruction semantics and that's what makes them smart.
But they all (normal pointers, shared_ptr, auto_ptr, iterators, etc
etc) still have reference semantics.  The proposed 'copy_ptr' does not
have reference semantics, and I already suggested in one of my first
posts that what you are looking for is really some kind of "variant".
As Sean Parent mentioned, something like boost::any with a template
parameter would probably be more intuitive.

Sean, do you have an interface for this class that you could post to
the NG?


> And it would be more practical if (ptr1 == ptr2) is actually comparing
> the objects being pointed to, instead of the address of the pointers.


This is precisely because pointers have reference semantics.  When you
compare pointers, you want to see whether they *refer* to the same
object.  You're checking the identity of the object, not the value of
the object.  If you want to compare values, then don't use a pointer.

-shez-

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]