Smart Pointer Issue

K

kmakaron11

Hello, I have the following classes:
class ServiceBase
{
public:
ServiceBase() {}
~ServiceBase() {}
void Stop() {}

};

class ServiceDerivate:public ServiceBase
{
public:
ServiceDerivate() {}
~ServiceDerivate() {}

};

And I have linked smart pointer class which, does not destroy, but
calls Stop method on its destruction:

template <class X> class ServicePtr
{
public:
explicit ServicePtr(X* p = 0) throw()
: itsPtr(p) {itsPrev = itsNext = this;}
~ServicePtr()
{release();}
ServicePtr(const ServicePtr& r) throw()
{acquire(r);}

ServicePtr& operator=(const ServicePtr& r)
{
if (this != &r) {
release();
acquire(r);
}
return *this;
}

X& operator*() const throw() {return *itsPtr;}
X* operator->() const throw() {return itsPtr;}
X* get() const throw() {return itsPtr;}
bool unique() const throw() {return itsPrev ? itsPrev==this :
true;}

private:
X* itsPtr;
mutable const ServicePtr* itsPrev;
mutable const ServicePtr* itsNext;

void acquire(const ServicePtr& r) throw()
{ // insert this to the list
itsPtr = r.itsPtr;
itsNext = r.itsNext;
itsNext->itsPrev = this;
itsPrev = &r;
r.itsNext = this;
}

void release()
{ // erase this from the list, delete if unique
if (unique())
itsPtr->Stop();
else {
itsPrev->itsNext = itsNext;
itsNext->itsPrev = itsPrev;
itsPrev = itsNext = 0;
}
itsPtr = 0;
}

};

Since ServiceBase and ServiceDerivated have to be dynamic castable i
wish I could use a pool of ServiceBase classes, and upon request to
spawn new ServicePtr holding dynamic_cast to ServiceBase. Sipmle
example:

int main()
{
ServicePtr<ServiceBase> sbase;
ServicePtr<ServiceDerivate> sderivate;

sderivate=sbase;

return 0;

}

which, produces:
"no matching function for call to
'ServicePtr<ServiceDerivate>::eek:perator=(ServicePtr<ServiceBase>&)'
note: candidates are: ServicePtr<X>& ServicePtr<X>::eek:perator=(const
ServicePtr<X>&) [with X = ServiceDerivate]

Can anybody help with this. Probably I am missing something.
I tryied to overload:
ServicePtr& operator=(const ServicePtr<ServiceBase>& r)
but I did not compiled either.
 
A

anon

Hello, I have the following classes:
class ServiceBase
{
public:
ServiceBase() {}
~ServiceBase() {}

Since you want to delete derived objects through the pointer/reference
of the base class, this destructor has to be virtual
void Stop() {}

};

class ServiceDerivate:public ServiceBase
{
public:
ServiceDerivate() {}
~ServiceDerivate() {}

};

And I have linked smart pointer class which, does not destroy, but
calls Stop method on its destruction:

template <class X> class ServicePtr
{
public:
explicit ServicePtr(X* p = 0) throw()
: itsPtr(p) {itsPrev = itsNext = this;}
~ServicePtr()
{release();}
ServicePtr(const ServicePtr& r) throw()
{acquire(r);}

ServicePtr& operator=(const ServicePtr& r)
{
if (this != &r) {
release();
acquire(r);
}
return *this;
}

ServicePtr& operator=( ServicePtr<ServiceBase>& r)
{
release();

ServicePtr cpyObj( dynamic_cast<X*> (r.get()));
r.release();
acquire(cpyObj);
cpyObj.release();

return *this;
}

This might do what you want, but it is a dirty hack. There are probably
better ways (which I couldn't think of right now :( )
X& operator*() const throw() {return *itsPtr;}
X* operator->() const throw() {return itsPtr;}
X* get() const throw() {return itsPtr;}
bool unique() const throw() {return itsPrev ? itsPrev==this :
true;}

private:
X* itsPtr;
mutable const ServicePtr* itsPrev;
mutable const ServicePtr* itsNext;

void acquire(const ServicePtr& r) throw()
{ // insert this to the list
itsPtr = r.itsPtr;
itsNext = r.itsNext;
itsNext->itsPrev = this;
itsPrev = &r;
r.itsNext = this;
}

void release()
{ // erase this from the list, delete if unique
if (unique())
itsPtr->Stop();
else {
itsPrev->itsNext = itsNext;
itsNext->itsPrev = itsPrev;
itsPrev = itsNext = 0;
}
itsPtr = 0;
}

};

Since ServiceBase and ServiceDerivated have to be dynamic castable i
wish I could use a pool of ServiceBase classes, and upon request to
spawn new ServicePtr holding dynamic_cast to ServiceBase. Sipmle
example:

int main()
{
ServicePtr<ServiceBase> sbase;
ServicePtr<ServiceDerivate> sderivate;

sderivate=sbase;

return 0;

}

which, produces:
"no matching function for call to
'ServicePtr<ServiceDerivate>::eek:perator=(ServicePtr<ServiceBase>&)'
note: candidates are: ServicePtr<X>& ServicePtr<X>::eek:perator=(const
ServicePtr<X>&) [with X = ServiceDerivate]

Can anybody help with this. Probably I am missing something.
I tryied to overload:
ServicePtr& operator=(const ServicePtr<ServiceBase>& r)
but I did not compiled either.

Off course, because ServicePtr<ServiceBase> and
ServicePtr<ServiceDerivate> are two independent types.
 
S

SG

Hello, I have the following classes:
class ServiceBase
{
        public:
                ServiceBase() {}
                ~ServiceBase() {}
[...]

ServicePtr& operator=( ServicePtr<ServiceBase>& r)
         {
             release();

             ServicePtr cpyObj( dynamic_cast<X*> (r.get()));
             r.release();
             acquire(cpyObj);
             cpyObj.release();

             return *this;
         }

dynamic_castis not going to work on non-polymorphic types.

Cheers!
SG
 
K

kmakaron11

There would be virtual dtor, I forgot to write it, when composing the
example above.
 
A

anon

SG said:
Hello, I have the following classes:
class ServiceBase
{
public:
ServiceBase() {}
~ServiceBase() {}
[...]

ServicePtr& operator=( ServicePtr<ServiceBase>& r)
{
release();

ServicePtr cpyObj( dynamic_cast<X*> (r.get()));
r.release();
acquire(cpyObj);
cpyObj.release();

return *this;
}

dynamic_castis not going to work on non-polymorphic types.

In this specific example it will work, but as I said it is a hack.
 
K

kmakaron11

I will test it tommorrow and will provide some feedback on final
ServicePtr class. Thank you anon :)
 
A

anon

SG said:
Hello, I have the following classes:
class ServiceBase
{
public:
ServiceBase() {}
~ServiceBase() {}
[...]

ServicePtr& operator=( ServicePtr<ServiceBase>& r)
{
release();

ServicePtr cpyObj( dynamic_cast<X*> (r.get()));
r.release();
acquire(cpyObj);
cpyObj.release();

return *this;
}

dynamic_castis not going to work on non-polymorphic types.

Cheers!
SG

This solves the problem. Anyone trying something stupid with the
template will notice :

ServicePtr& operator=( ServicePtr<ServiceBase>& r)
{
release();

X *tmp = dynamic_cast<X*> (r.get());
assert( NULL != tmp );

ServicePtr cpyObj( tmp );
r.release();
acquire(cpyObj);
cpyObj.release();

return *this;
}
 
J

James Kanze

Hello, I have the following classes:
class ServiceBase
{
public:
ServiceBase() {}
~ServiceBase() {}
void Stop() {}
};

class ServiceDerivate:public ServiceBase
{
public:
ServiceDerivate() {}
~ServiceDerivate() {}
};
And I have linked smart pointer class which, does not destroy,
but calls Stop method on its destruction:
template <class X> class ServicePtr
{ [...]
};
Since ServiceBase and ServiceDerivated have to be dynamic
castable i wish I could use a pool of ServiceBase classes, and
upon request to spawn new ServicePtr holding dynamic_cast to
ServiceBase.

I'm not sure I understand. In your example, there are no
virtual functions, so the classes aren't polymorphic. I
presume, however, that this is just an oversight in the example.
And of course, you don't need dynamic_cast to convert from
ServiceDerivate to ServiceBase; that's an implicit conversion.
Sipmle example:
int main()
{
ServicePtr<ServiceBase> sbase;
ServicePtr<ServiceDerivate> sderivate;

return 0;
}
which, produces:
"no matching function for call to
'ServicePtr<ServiceDerivate>::eek:perator=(ServicePtr<ServiceBase>&)'
note: candidates are: ServicePtr<X>& ServicePtr<X>::eek:perator=(const
ServicePtr<X>&) [with X = ServiceDerivate]

It also doesn't make sense unless sbase actually points to a
ServiceDerivate. If you want to support this, with dynamic
checking, you can add something like the following to your
ServicePtr:

template< typename T >
ServicePtr& operator=( ServicePtr< T > const& other )
{
X* tmp = dynamic_cast< X* >( other.get() ) ;
// rest of processing, however...
}

In this case, I'd probably derive ServicePtr from a non-template
ServicePtrBase which contained and handled the links.
Otherwise, you'll have to make all instances of the template
friends of the other instances. (As it stands,
ServicePtr< ServiceBase > cannot access any of the members of a
ServicePtr said:
Can anybody help with this. Probably I am missing something.
I tryied to overload:
ServicePtr& operator=(const ServicePtr<ServiceBase>& r)
but I did not compiled either.

What was the error message? And what did the code look like?

As mentionned above, you're likely to have problems with
accessing private data members; each instantiation of the
template is a separate, unrelated class. Moving the list
handling down to a common, non-template base class should solve
that. (It also has the advantage that you can get it out of the
header files, reducing their size.)
 
T

Thomas J. Gritzan

anon said:
SG said:
(e-mail address removed) wrote:
Hello, I have the following classes:
class ServiceBase
{
public:
ServiceBase() {}
~ServiceBase() {}
[...]

ServicePtr& operator=( ServicePtr<ServiceBase>& r)
{
release();

ServicePtr cpyObj( dynamic_cast<X*> (r.get()));
r.release();
acquire(cpyObj);
cpyObj.release();

return *this;
}

dynamic_castis not going to work on non-polymorphic types.

Cheers!
SG

This solves the problem. Anyone trying something stupid with the
template will notice :

Doesn't work.
ServicePtr& operator=( ServicePtr<ServiceBase>& r)
{
release();

X *tmp = dynamic_cast<X*> (r.get());
assert( NULL != tmp );

ServicePtr cpyObj( tmp );

This will make a smart pointer which owns the tmp pointer.
r.release();

This lets r release its pointee, after that either its pointee is
deleted, or there's another smart pointer holding ownership.
acquire(cpyObj);
cpyObj.release();

return *this;
}

Here the class either stores an already deleted pointer, or there are
two families of smart pointers who owns the pointee.

Altough this smart pointer doesn't delete the pointee but call its
Stop() function, I don't think it's a good idea to call Stop() while
still using it.
 

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,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top