I am writing code for smart pointers as an exercise. Using tutorials online (1 , 2) I have developed a normal smart-pointer class with reference counting. The problem is I am unable to figure out the following:
when the smart pointer detects that no more references exist to a particular object, it must delete the object via a pointer to the original type, even if the template argument of the final smart pointer is of a base type. This is to avoid object slicing for non-virtual destructors.
How can I achieve that. Basically my code looks like below (from the tutorial).
template < typename T > class SP
{
private:
T* pData; // pointer
RC* reference; // Reference count
public:
SP() : pData(0), reference(0)
{
// Create a new reference
reference = new RC();
// Increment the reference count
reference->AddRef();
}
SP(T* pValue) : pData(pValue), reference(0)
{
// Create a new reference
reference = new RC();
// Increment the reference count
reference->AddRef();
}
SP(const SP<T>& sp) : pData(sp.pData), reference(sp.reference)
{
// Copy constructor
// Copy the data and reference pointer
// and increment the reference count
reference->AddRef();
}
~SP()
{
// Destructor
// Decrement the reference count
// if reference become zero delete the data
if(reference->Release() == 0)
{
delete pData;
delete reference;
}
}
T& operator* ()
{
return *pData;
}
T* operator-> ()
{
return pData;
}
SP<T>& operator = (const SP<T>& sp)
{
// Assignment operator
if (this != &sp) // Avoid self assignment
{
// Decrement the old reference count
// if reference become zero delete the old data
if(reference->Release() == 0)
{
delete pData;
delete reference;
}
// Copy the data and reference pointer
// and increment the reference count
pData = sp.pData;
reference = sp.reference;
reference->AddRef();
}
return *this;
}
};
EDIT:
To achieve that I have to have a pointer to the original type.
I have posted a question here: delete via a pointer to Derived, not Base
But Now since viewing the comments and answers I think both are related. I have the constructor:
template <typename T>
template <typename U>
Sptr<T>::Sptr(U* u) : obj(u),ref(NULL) {
//do something
ref = new RC();
ref->AddRef();
}
Now consider Sptr<Base1> sp(new Derived);
where Derived
is derived from Base1
. Base1 has protected constructor/destructor.
Which is storing for an object of type T
But I need to store it through an object of type U. I need to preserve that. How can I do that?
Your smart pointer needs 3 chunks of information.
First, the pointer to the data (T*
or something).
Second, your reference count: std::atomic<int>
or something.
Third, your destruction function (std::function<void(T*)>
or something).
When the smart pointer is first created, that destruction function is created. When your smart pointer is copied to another smart pointer, this destruction function is copied. If the type of the new smart pointer doesn't match the old, that destruction function gets wrapped up in a type-compatible way (does std::function<void(Base*)> = std::function<void(Derived*)>
work out of the box? Regardless, you are basically doing that).
By default, this destruction function is just delete t
, but as a side benefit, this allows the users of your smart pointer to pass in a destruction function, which isn't always delete t
.
Amusingly, on the equivalent of reset
, you replace your destruction function. So you could actually make the signature of the destruction function be std::function<void()>
, which makes moving it between T
and U
type smart pointers a tad easier.
template < typename T > class SP
{
private:
T* pData; // pointer
RC* reference; // Reference count
std::function<void()> destroyData;
public:
template<typename U>
SP(U* pValue):
pData(pValue),
reference(nullptr),
// store how to destroy pValue now, for later execution:
destroyData([pValue]()->void{
delete pValue;
})
{
// Create a new reference
reference = new RC();
// Increment the reference count
reference->AddRef();
}
// similar for operator=, and you may have to do something for SP<T> as well:
template<typename U>
SP(const SP<U>& sp):
pData(sp.pData),
reference(sp.reference),
destroyData(sp.destroyData)
{
// Copy constructor
// Copy the data and reference pointer
// and increment the reference count
reference->AddRef();
}
template<typename U>
SP<T>& operator = (const SP<U>& sp)
{
// blah blah blah, then
destroyData = sp.destroyData;
}
~SP()
{
// Destructor
// Decrement the reference count
// if reference become zero delete the data
if(reference->Release() == 0)
{
delete reference;
destroyData(); // here I destroyed it!
}
}
};
or something like that
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With