C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

smart pointers shortcomings question/repair

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
T. Lovset
Guest





PostPosted: Fri Jul 16, 2004 11:23 am    Post subject: smart pointers shortcomings question/repair Reply with quote



Hi, everyone.

Having used my own smart pointers for years, I find it strange that
both boost::shared_ptr and Loki::SmartPtr still lack an obvious
feature. One of the goals for smart pointers is that they should mimic
the syntax of regular pointers as closely as possible, which is
important when converting from regular to smart pointers. Recent
updates to boost::shared_ptr even safely allows the syntax: if (p) ...
Why then, is the ability to initialize and assign to NULL still left
out?

For boost::shared_ptr, it can be achieved simply by:

template <class T> class shared_ptr {
struct null_tag {};
public:
shared_ptr(null_tag* = NULL) : px(0), pn() {}
shared_ptr& operator=(null_tag*) { reset(); return *this; }
...

which allows code like:
boost::shared_ptr<int> p = NULL;
...
p = NULL;

---

A second, but more serious problem with current implementations of
smart pointers is illustrated in the following:

class Widget {
public:
Widget(Danger* d) : m_danger(d) {}
...
private:
Danger* m_danger;

If we change the attribute m_danger to type boost::shared_ptr<Danger>,
but fail to observe that the constructor takes a raw Danger pointer,
this code still compiles fine, but has now become a time-bomb. The
correct code would be to have a const boost::shared_ptr<Danger>& as
ctor-argument. However, shared_ptr should rather have disallowed
initialization directly from a regular pointer.

The way I have overcome this problem, is by wrapping a handle class
around the raw pointers:

// this class could be more sophisticated...
template <typename T> class new1_handle {
public:
explicit new1_handle(T* p) : px(p) {}
T* release() const { return px; }
private:
T* px;
};

template <typename T>
inline new1_handle<T> make_new1_handle(T* p) {
return new1_handle<T>(p);
}

Adding a dreaded macro makes it easier for real-life usage:
#define new1(X) make_new1_handle(new X)

// example
smart_ptr<Widget> w = new1( Widget(...) );

The ctor is then something like:

template <typename U> smart_ptr(const new1_handle<U>& m)
: px(m.release()) {}


I hope these ideas will emerge in the standard smart pointer
implementations soon. For me, they are simply too important to be left
out.

Regards, TL.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Joe Gottman
Guest





PostPosted: Sat Jul 17, 2004 10:17 am    Post subject: Re: smart pointers shortcomings question/repair Reply with quote




"T. Lovset" <tylo (AT) start (DOT) no> wrote

Quote:
Hi, everyone.

Having used my own smart pointers for years, I find it strange that
both boost::shared_ptr and Loki::SmartPtr still lack an obvious
feature. One of the goals for smart pointers is that they should mimic
the syntax of regular pointers as closely as possible, which is
important when converting from regular to smart pointers. Recent
updates to boost::shared_ptr even safely allows the syntax: if (p) ...
Why then, is the ability to initialize and assign to NULL still left
out?

For boost::shared_ptr, it can be achieved simply by:

template <class T> class shared_ptr {
struct null_tag {};
public:
shared_ptr(null_tag* = NULL) : px(0), pn() {}
shared_ptr& operator=(null_tag*) { reset(); return *this; }
...

which allows code like:
boost::shared_ptr<int> p = NULL;
...
p = NULL;


Unfortunately this won't work. shared_ptr also has a constructor
template <class U> shared_ptr(U *pu);

When you later say
shared_ptr<int> p(NULL);

the compiler won't know which constructor to call; NULL can be converted to
an int* or to a null_tag *. There is a proposal now before the standard
committee which would fix this problem by creating a special value called
nullptr, which can be cast to any pointer type, but not to int, bool, etc.
The value nullptr would have a special type, called nullptr_t. If this
proposal is added, we could overload shared_ptr's constructor to take a
nullptr_t parameter. Here is a link to the proposal.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1601.pdf

Joe Gottman


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
T. Lovset
Guest





PostPosted: Tue Aug 03, 2004 11:24 am    Post subject: Re: smart pointers shortcomings question/repair Reply with quote



"Joe Gottman" <jgottman (AT) carolina (DOT) rr.com> wrote


Quote:
Why then, is the ability to initialize and assign to NULL still left
out?

For boost::shared_ptr, it can be achieved simply by:

template <class T> class shared_ptr {
struct null_tag {};
public:
shared_ptr(null_tag* = NULL) : px(0), pn() {}
shared_ptr& operator=(null_tag*) { reset(); return *this; }
...

which allows code like:
boost::shared_ptr<int> p = NULL;
...
p = NULL;


Unfortunately this won't work. shared_ptr also has a constructor
template <class U> shared_ptr(U *pu);

When you later say
shared_ptr<int> p(NULL);

the compiler won't know which constructor to call; NULL can be converted to
an int* or to a null_tag *.

Thanks Joe, you are right, but in the second part of my post I meant
to suggest to use:
template <class U> shared_ptr(const new1_handle<U>& h);
INSTEAD of
explicit template <class U> shared_ptr(U *pu);

It then will work, and this will give an important safety benefit (see
post) in addition to a more intuitive usage and ease when switching
back and forth between raw and smart pointers:
shared_ptr<Widget> mySmartPtr = new1( Widget(name, type) );
mySmartPtr = NULL
mySmartPtr = new1( Widget(name, type) );

rather than:
shared_ptr<Widget> mySmartPtr( new Widget(name, type) );
mySmartPtr.reset();
mySmartPtr.reset( new Widget(name, type) );

This also imply using:
template <class U> operator=(new1_handle<U>& h);
instead of (or maybe here in addition to)
template <class U> reset(U *pu);

PS: I know the macro "new1" will not be accepted in an implementaton,
but you can do without it. Changing the name of function
make_new1_handle() to rawptr() or something similar, may improve
readability. This will give the safe and explicit syntax:
mySmartPtr = rawptr( new Widget() );

Quote:
There is a proposal now before the standard
committee which would fix this problem by creating a special value called
nullptr, which can be cast to any pointer type, but not to int, bool, etc.
The value nullptr would have a special type, called nullptr_t. If this
proposal is added, we could overload shared_ptr's constructor to take a
nullptr_t parameter. Here is a link to the proposal.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1601.pdf

Yes, thanks. This would also solve the first issue in my post,

although sometime in the future.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.