I based this implementation on CountedPtr in The C++ Standard Library book by Nicolai Josuttis (page 222) and also available online here.
I know that I can use the C++11 smart pointers but this is a learning exercise and also for some projects an earlier compiler must be used.
I didn't understand the need for the actual reference counter to be a pointer so I just used a standard integer. Maybe that introduces a bug, not sure.
My main concern is about the object lifecycle. Does the reference counter as a straight integer cause a bug? Any feedback will be much appreciated.
Here is the smart pointer class:
#ifndef SMARTPOINTER_HPP__
#define SMARTPOINTER_HPP__
#include <iostream>
template<typename T>
class sp {
public:
sp(T* ptr) : ptr_(ptr), ref_cnt_(1) {
std::cout << "sp ctor: " << ptr_ << ", ref_cnt_: " << ref_cnt_ << std::endl;
}
T& operator*() { return *ptr_; }
T* operator->() { return ptr_; }
sp(const sp<T>& rhs) : ptr_(rhs.ptr_), ref_cnt_(rhs.ref_cnt_) {
++ref_cnt_;
std::cout << "sp copy ctor: " << ptr_ << ", ref_cnt_: " << ref_cnt_ << std::endl;
}
sp& operator=(const sp& rhs) {
if(this != &rhs) {
*this = rhs;
++ref_cnt_;
std::cout << "sp assignment: " << ptr_ << ", ref_cnt_: " << ref_cnt_ << std::endl;
}
return *this;
}
~sp() {
if(ptr_)
std::cout << "~sp: " << ptr_ << ", ref count: " << ref_cnt_ << std::endl;
--ref_cnt_;
if(ref_cnt_ == 0)
delete ptr_;
}
bool operator==(const T& that) const { return ptr_ == that.ptr_; }
bool operator==(T* that) const { return ptr_ == that; }
bool operator!=(const sp& that) const { return ptr_ != that.ptr_; }
bool operator!=(sp* that) const { return ptr_ != that; }
private:
T* ptr_;
unsigned ref_cnt_;
};
#endif //SMARTPOINTER_HPP__
Here is my code to exercise:
#include <iostream>
#include <string.h>
#include "smart_pointer.hpp"
class name {
public:
name(const char* label) : label_(label) {}
const char* get_name() const { return label_; }
unsigned length() const { return strlen(label_); }
private:
const char* label_;
};
int main() {
{
std::cout << "Test with ints\n";
sp<int> myptr1 = new int(3);
*myptr1 = 4;
std::cout << "number: " << *myptr1 << std::endl;
sp<int> myp2(myptr1);
sp<int> myp3(myptr1);
sp<int> myp4 = myptr1;
}
{
std::cout << "Test with name object\n";
sp<name> myname = new name("Andrew");
std::cout << myname->get_name() << " has length: " << myname->length() << std::endl;
sp<name> myname2(myname);
}
return 0;
}
I get this output:
Test with ints sp ctor: 004C7A80, ref_cnt_: 1 number: 4 sp copy ctor: 004C7A80, ref_cnt_: 2 sp copy ctor: 004C7A80, ref_cnt_: 2 sp copy ctor: 004C7A80, ref_cnt_: 2 ~sp: 004C7A80, ref count: 2 ~sp: 004C7A80, ref count: 2 ~sp: 004C7A80, ref count: 2 ~sp: 004C7A80, ref count: 1 Test with name object sp ctor: 004C7A80, ref_cnt_: 1 Andrew has length: 6 sp copy ctor: 004C7A80, ref_cnt_: 2 ~sp: 004C7A80, ref count: 2 ~sp: 004C7A80, ref count: 1
SMARTPOINTER_HPP__
don't use them. \$\endgroup\$