I am writing this smart pointer as a learning exercise. Any feedback would be most appreciated.
Any flaws? Have I missed any test cases?
smart_pointer.hpp:
#ifndef SMARTPOINTER_HPP_
#define SMARTPOINTER_HPP_
#include <iostream>
template<typename T>
class sp {
public:
sp(T* ptr) : ptr_(ptr), ref_cnt_(new unsigned(1)) {
std::cout << "sp ctor. Address: " << ptr_ << ", ref_cnt_: " << *ref_cnt_ << '\n';
}
T& operator*() { return *ptr_; }
const T& operator*() const { return *ptr_; }
T* operator->() { return ptr_; }
const T* operator->() const { return ptr_; }
// access to raw ptr
T* get() { return ptr_; }
sp(const sp<T>& rhs) : ptr_(rhs.ptr_), ref_cnt_(rhs.ref_cnt_) {
addref();
std::cout << "sp copy ctor: " << ptr_ << ", ref_cnt_: " << *ref_cnt_ << '\n';
}
sp& operator=(const sp& rhs) {
if(this != &rhs) {
try_delete();
ptr_ = rhs.ptr_;
ref_cnt_ = rhs.ref_cnt_;
addref();
std::cout << "sp assignment: " << ptr_ << ", ref_cnt_: " << *ref_cnt_ << '\n';
}
return *this;
}
~sp() {
std::cout << "~sp. Address: " << ptr_ << ", ref count before remove_ref: " << *ref_cnt_ << '\n';
try_delete();
}
private:
unsigned addref() {
return ++*ref_cnt_;
}
unsigned remove_ref() {
return --*ref_cnt_;
}
void try_delete() {
if(remove_ref() == 0) {
std::cout << "try_delete(): finally deleting ptr_ at address: " << ptr_ << ", ref count: " << *ref_cnt_ << '\n';
delete ref_cnt_;
delete ptr_;
}
}
T* ptr_; // raw ptr
unsigned* ref_cnt_; // shared ownership
};
#endif //SMARTPOINTER_HPP_
Code to exercise:
#include <iostream>
#include <vector>
#include "smart_pointer.hpp"
// useless class just used to test with object more complex than int
class tester {
public:
tester(const int id, const char* name) : id_(id), name_(name) {}
const char* const get_name() const { return name_; }
const int get_id() const { return id_; }
private:
const int id_;
const char* const name_;
};
// global vector to hold smart pointer
std::vector< sp<int> > gvs;
int main() {
{
std::cout << "Test with ints\n";
sp<int> myptr1 = new int(3);
*myptr1 = 4;
std::cout << "number: " << *myptr1 << '\n';
{
// test usage in collection
std::vector< sp<int> > vs;
vs.push_back(myptr1);
}
// global collection
gvs.push_back(myptr1);
// copying
sp<int> myp2(myptr1);
sp<int> myp3(myptr1);
sp<int> myp4 = myptr1;
}
{
std::cout << "Test with more complex objects\n";
sp<tester> spt = new tester(1, "Keira Knightley");
tester* p = spt.get();
std::cout << "Name: " << p->get_name() << ", id: " << p->get_id() << '\n';
// copying
sp<tester> spt2 = spt;
sp<tester> spt3(spt);
sp<tester> spt4(new tester(2, "Cate Blanchett"));
// re-assign
spt = new tester(3, "Natalie Portman");
}
return 0;
}