[code review] linked_ptr

T

Thomas J. Gritzan

Hi!

I wrote (yet another) linked_ptr implementation, based on discussions
about boost's linked_ptr (I can't find the source code) and other
discussions about smart pointers, mainly by Andrei Alexandrescu.

Recently there were mentioned linked_ptrs in c.l.c++ and *.moderated, so
I decided to put out the source code.

The source can be found here:
http://pastebin.com/m5f222fa9

** Introduction **

All the other linked_ptr implementations on the web don't support a
custom deleter, and don't support ptr<derived> to ptr<base> conversions.

This implementation is intended as a drop-in replacement for shared_ptr
for some uses, so it tries to mimic its interface. It supports implicit
derived to base conversions, explicit
{static,const,dynamic}_pointer_cast, a custom deleter and a form of
policy class.

Using the policy class, two extra member functions are injected into the
linked_ptr for array types: get(index) and operator[], while op* and
op-> are disabled. So you can have linked_ptr<type[]>. For array types,
the class supports aliasing, so you can do pointer arithmetic on the
smart pointer (++, --, +=, -=, +, -).

Feel free to comment on design, sense and functionality.

** Unsolved problem **

There's one issue I'd like to have a solution for. You can set a custom
deleter on class basis like this:

template <>
struct linked_ptr_deleter<SomeClass>
{
void operator()(SomeClass* ptr) const { ptr->release(); }
};

But how do I set a custom deleter for all classes which are derived from
SomeClass without specializing the template for every such class?
 
K

kmakaron11

I have not read the class yet. But does it support ptr<base> to
ptr<derived> conversions. I need such a functionality, so I can hold a
pool of ptr<base> objects, and upon request to return ptr<derivated>,
off cource if it is dynamic_castable.If it does not support this, can
we add it to your class?
 
T

Thomas J. Gritzan

(e-mail address removed) write:
I have not read the class yet. But does it support ptr<base> to
ptr<derived> conversions. I need such a functionality, so I can hold a
pool of ptr<base> objects, and upon request to return ptr<derivated>,
off cource if it is dynamic_castable.If it does not support this, can
we add it to your class?

The class supports static_pointer_cast and dynamic_pointer_cast similar
to shared_ptr.
But you have to make sure, that the pointee can be deleted using both
the source type and the destination type, for example by making the base
destructor virtual.
 
K

kmakaron11

I am not so very experienced though. Can you provide small usage
example. Defining deletion policy, and base to derivated, and
derivated to base operations. Thanks.
 
S

SG

I wrote (yet another) linked_ptr implementation, based on discussions
about boost's linked_ptr (I can't find the source code) and other
discussions about smart pointers, mainly by Andrei Alexandrescu.

It's an insteresting design. I only skimmed through the code. It
seems you even try to support pointer arithmetic and flexible deleters
depending on the template parameter.

I didn't see any SFINAE, though. I think you could improve
compilation error messages with SFINAE when a user tries to convert
pointer Y* to X* where there is no implicit conversion. I find SFINAE
for these cases quite useful. A metafunction
is_convertible<X,Y>::value isn't hard to implement if you know the
metaprogramming tricks.

Also, you could make client code less error-prone by disallowing
pointer type conversions for arrays. This is doomed to fail anyways.

my 2 cents,
SG
 
T

Thomas J. Gritzan

I am not so very experienced though. Can you provide small usage
example. Defining deletion policy, and base to derivated, and
derivated to base operations. Thanks.

Simple usage example code:
http://pastebin.com/m4349e4ab

You can provide a custom deleter by specializing linked_ptr_deleter, but
you have to do it for every derived class, too, yet:

// deleter for base class:
template <>
struct linked_ptr_deleter<Base>
{
void operator()(Base* ptr) const { if (ptr) ptr->release(); }
};

// derived class uses base class deleter:
template <>
struct linked_ptr_deleter<Derived> : linked_ptr_deleter<Base> {};

I hope I'll find a solution that lets you provide a custom deleter for
the base class and all derived classes at once.
 
K

kmakaron11

My custom deleter is:

template <>
struct ServicePtr_deleter<ServiceBase> {
void operator()(ServiceBase* ptr) const { ptr->Stop(); }
};

I am getting ptr=0x0(And SEGFAULT) at ServicePtr<X> tmp(*this)
destruction in methtod below.
What do you mean by "release pointee in destructor if not shared"?
template<typename X>
template<typename Y>
inline void ServicePtr<X>::reset(ServicePtr<Y> const& other,
pointer_type ptr)
{
if (&link != &other.link)
{
ServicePtr<X> tmp(*this); // release pointee in destructor if
not shared

link.reset(other.link); // move this smart pointer to the
new list
this->set_pointee(other, ptr); // reset the pointee
}
else
this->set_pointee(other, ptr); // reset the pointee
}

I am also getting the following warning upon compilation with gcc
3.3.6:
linked_ptr.h:313: warning: `linked_ptr<X>::unspecified_bool_type is
implicitly a typename
linked_ptr.h:313: warning: implicit typename is deprecated, please see
the documentation for details
 
T

Thomas J. Gritzan

My custom deleter is:

template <>
struct ServicePtr_deleter<ServiceBase> {
void operator()(ServiceBase* ptr) const { ptr->Stop(); }

You have to check for null pointer "delete":

if (ptr)
ptr->Stop();
};

I am getting ptr=0x0(And SEGFAULT) at ServicePtr<X> tmp(*this)
destruction in methtod below.
What do you mean by "release pointee in destructor if not shared"?

Only the last linked_ptr releases (i.e. deletes) the pointer.
template<typename X>
template<typename Y>
inline void ServicePtr<X>::reset(ServicePtr<Y> const& other,
pointer_type ptr)
{
if (&link != &other.link)
{
ServicePtr<X> tmp(*this); // release pointee in destructor if
not shared

link.reset(other.link); // move this smart pointer to the
new list
this->set_pointee(other, ptr); // reset the pointee
}
else
this->set_pointee(other, ptr); // reset the pointee
}

I am also getting the following warning upon compilation with gcc
3.3.6:
linked_ptr.h:313: warning: `linked_ptr<X>::unspecified_bool_type is
implicitly a typename
linked_ptr.h:313: warning: implicit typename is deprecated, please see
the documentation for details

Maybe I forgot a "typename" somewhere. Visual C++ isn't so strict about it.
 
T

Thomas J. Gritzan

My custom deleter is:

template <>
struct ServicePtr_deleter<ServiceBase> {
void operator()(ServiceBase* ptr) const { ptr->Stop(); }
};

I decided to handle the "null pointer" delete in the linked_ptr class.
With the new version, the above deleter will work.
I am also getting the following warning upon compilation with gcc
3.3.6:
linked_ptr.h:313: warning: `linked_ptr<X>::unspecified_bool_type is
implicitly a typename
linked_ptr.h:313: warning: implicit typename is deprecated, please see
the documentation for details

I added the typename, too.

New version:
http://pastebin.com/m223560ad
 
K

kmakaron11

It works like hell now. I'll put your class in my tool collection.
Thank you, very much Thomas.
 
T

Thomas J. Gritzan

SG said:
It's an insteresting design. I only skimmed through the code. It
seems you even try to support pointer arithmetic and flexible deleters
depending on the template parameter.

Yes. The custom deleters were the reason to write my own implementation.

I read about a proposal for shared_ptr to add an aliasing constructor
and wondered if it was possible for linked_ptr, too. It might be useful
to have a pointer pointing into an array. When aliasing worked, pointer
arithmetic was a small step. The smart pointer allows to iterate through
an array now, using a start/end pair.
I didn't see any SFINAE, though. I think you could improve
compilation error messages with SFINAE when a user tries to convert
pointer Y* to X* where there is no implicit conversion. I find SFINAE
for these cases quite useful. A metafunction
is_convertible<X,Y>::value isn't hard to implement if you know the
metaprogramming tricks.

Thank you for this suggestion. I started to read about SFINAE and found
a trick to declare a special deleter for a base and its subclasses.

You can just write a deleter and add this line:
DECLARE_LINKED_PTR_BASE_DELETER(Base, linked_ptr_deleter<Base>);

The new code is here:
http://pastebin.com/m472c231d

But I don't think that the error messages could be improved. Isn't the
following clear enough:
Also, you could make client code less error-prone by disallowing
pointer type conversions for arrays. This is doomed to fail anyways.

Conversion from linked_ptr<Derived[]> to linked_ptr<Base[]> were already
disallowed, but I added some code to disable initializations of
linked_ptr<Base[]> by Derived* pointers.
 
T

Thomas J. Gritzan

Answering to myself...
You can provide a custom deleter by specializing linked_ptr_deleter, but
you have to do it for every derived class, too, yet:

// deleter for base class:
template <>
struct linked_ptr_deleter<Base>
{
void operator()(Base* ptr) const { if (ptr) ptr->release(); }
};

// derived class uses base class deleter:
template <>
struct linked_ptr_deleter<Derived> : linked_ptr_deleter<Base> {};

I hope I'll find a solution that lets you provide a custom deleter for
the base class and all derived classes at once.

I found a way using SFINAE.

Use the new version of the file: http://pastebin.com/m472c231d
and add a special line after the deleter declaration:

DECLARE_LINKED_PTR_BASE_DELETER(Base, linked_ptr_deleter<Base>);

The null pointer check isn't neccessary anymore, too.
 
K

kmakaron11

In folling class g++, warns that all member functions are private.

template <typename From, typename To>

class is_convertible said:

{

static From Make();

static false_type Test(...);

static true_type Test(To);



public:

enum { value = sizeof(Test(Make())) == sizeof(true_type) };

};
Can we do this warning dissapear. I personnaly added a public dummy
method, returning false.
 
T

Thomas J. Gritzan

In folling class g++, warns that all member functions are private.

template <typename From, typename To>



{

static From Make();

static false_type Test(...);

static true_type Test(To);



public:

enum { value = sizeof(Test(Make())) == sizeof(true_type) };

};
Can we do this warning dissapear. I personnaly added a public dummy
method, returning false.

Huh. What's this warning for?

Remove -Wctor-dtor-privacy from gccs command line or
add an empty constructor in the public section.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,822
Latest member
israfaceZa

Latest Threads

Top