I wrote an implementation of a shared pointer. I would like a review of it.
It seems to work, but running it through Valgrind shows that that it leaks memory somewhere in my tests, but I don't know where.
Here is my .h file:
#include <stdexcept>
//Try to create a smart pointer? Should be fun.
template <class T>
class rCPtr {
T* ptr;
T** ptrToPtr;
long* refCount;
public:
rCPtr()
{
try
{
ptr = new T;
ptrToPtr = &ptr;
refCount = new long;
*refCount = 1;
}
catch (...)
{
if (ptr)
delete ptr;
if (refCount)
delete refCount;
}
}
explicit rCPtr(T* pT)
{
try
{
ptr = pT;
ptrToPtr = &ptr;
refCount = new long;
*refCount = 1;
}
catch(...)
{
if (ptr)
delete ptr;
if (refCount)
delete refCount;
}
}
~rCPtr()
{
(*refCount)--;
if (*refCount <= 0)
{
delete ptr;
ptr = nullptr;
delete refCount;
refCount = nullptr;
}
}
// I wonder if this is even necessary?
bool exists() const {
return *ptrToPtr; // Will be null if already freed (SCRATCH THAT IT CRASHES)
}
//Copy
rCPtr(const rCPtr& other) : ptr(other.ptr), refCount(other.refCount)
{
(*refCount)++;
}
// If you pass another of same object.
rCPtr& operator=(const rCPtr &right)
{
if (this == &right) {return *this;}
T* leftPtr = ptr;
long* leftCount = refCount;
ptr = right.ptr;
refCount = right.refCount;
(*refCount)++;
(*leftCount)--;
// delete if no more references to the left pointer.
if (*leftCount <= 0)
{
delete leftPtr;
leftPtr = nullptr;
delete leftCount;
leftCount = nullptr;
}
return *this;
}
// This will create a 'new' object (call as name = new var) Make sure the type matches the one used for this object
rCPtr& operator=(const T* right)
{
if (right == ptr) {return *this;}
T* leftPtr = ptr;
long* leftCount = refCount;
ptr = right;
*refCount = 1; // New refCount will always be 1
(*leftCount)--;
if (*leftCount <= 0)
{
delete leftPtr;
leftPtr = nullptr;
delete leftCount;
leftCount = nullptr;
}
}
T* operator->() const
{
if (exists())
return *ptrToPtr;
else return nullptr;
}
T& operator*() const
{
if (exists())
return **ptrToPtr;
// I dont know what else to do here
throw std::out_of_range("Pointer is already deleted");
}
// Gives ref to ptr
// Pls don't try to delete this reference, the class should take care of that
const T& get() const
{
return *ptr; // This reference does not count to refCount
}
// if used in bool expressions if(rCPtr) {I think}
explicit operator bool() const
{
return *ptrToPtr;
}
// returns the number of references
long getRefCount() const
{
return *refCount;
}
// Will attempt to cast the stored pointer into a new type & return it
// You probably should not delete this one either
template <class X>
X* dCast()
{
try
{
// X must be poly morphic or else, the cast will fail and cause an compiler error.
auto casted = dynamic_cast<X*>(*ptrToPtr);
return casted;
}catch(const std::bad_cast& me)
{
return nullptr;
}
}
// Resets current instance, if other instances exist will not delete object
void reset()
{
(*refCount)--;
ptrToPtr = nullptr;
if (*refCount <= 0) // If the amount of references are 0 (negative count may explode ??)
{
delete ptr;
ptr = nullptr;
delete refCount;
refCount = nullptr;
}
}
};
//Notes just finished typing it up. It compiled so that is good
//Valgrind DOES NOT like it though
I will take the chance to say thank you to anyone who answers this
/ Edit: Thanks for everyone who helped with answering my questions! (And for putting up with all of them as well)