Created
March 19, 2012 18:01
-
-
Save erikkaplun/2121814 to your computer and use it in GitHub Desktop.
smartpointer (C++)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <vector> | |
#include <cassert> | |
#include <string> | |
using std::vector; | |
using std::cout; | |
using std::endl; | |
using std::string; | |
#define DEBUG | |
#include "smartpointer.h" | |
struct Spaceship : public smart<Spaceship> { | |
Spaceship() {} | |
}; | |
struct Missile : public smart<Missile> { | |
Spaceship::ptr spaceship; | |
Missile(Spaceship* s) : spaceship(s) {} | |
}; | |
void test1(); | |
void test2(Spaceship *); | |
void test3(); | |
void test4(); | |
void test5(); | |
int main() { | |
LOG("-- MAIN {"); | |
test1(); | |
LOG("-- TEST2 {"); | |
Spaceship::ptr ship = new Spaceship(); | |
test2(ship); | |
test3(); | |
test4(); | |
test5(); | |
LOG("-- } MAIN"); | |
// the ship passed to test2 will be freed here | |
} | |
void test1() { | |
LOG("-- TEST1 {"); | |
Spaceship::ptr ss = new Spaceship(); | |
assert(ss->numrefs() == 1); | |
Missile::ptr missile1 = new Missile(ss); | |
assert(ss->numrefs() == 2); | |
Missile::ptr missile2 = new Missile(ss); | |
assert(ss->numrefs() == 3); | |
delete ss; | |
assert(ss.wrapped == null); | |
assert(missile1->spaceship == null); | |
assert(missile2->spaceship == null); | |
LOG("-- } TEST1"); | |
// the missiles get auto-deleted, but the spaceship has | |
// already been deleted and won't be deleted twice. | |
} | |
void test2(Spaceship* ship) { | |
Missile::ptr missile = new Missile(ship); | |
// Missile will be freed when the pointer to it goes out of scope | |
// but the ship passed in to this function will not be freed | |
LOG("-- } TEST2"); | |
} | |
void test3() { | |
LOG("-- TEST3 {"); | |
Spaceship::ptr ship = new Spaceship(); | |
Missile::ptr missile1 = new Missile(ship); | |
missile1->spaceship = null; | |
assert(missile1->spaceship == null); | |
assert(ship != null); | |
LOG("-- } TEST3"); | |
} | |
void test4() { | |
LOG("-- TEST4 {"); | |
Spaceship::ptr ship = new Spaceship(); | |
ship = null; // Spaceship instance will be freed | |
LOG("-- } TEST4"); | |
} | |
void test5() { | |
LOG("-- TEST5 {"); | |
Spaceship::ptr ship = new Spaceship(); | |
Spaceship::ptr ship_alias = ship; | |
assert(ship->numrefs() == 2); | |
ship_alias = null; | |
assert(ship->numrefs() == 1); | |
ship_alias = (Spaceship*) ship; | |
assert(ship->numrefs() == 2); | |
ship_alias = null; | |
assert(ship->numrefs() == 1); | |
ship_alias = ship; | |
assert(ship->numrefs() == 2); | |
Spaceship::ptr ship_alias2 = ship; | |
assert(ship->numrefs() == 3); | |
ship_alias2 = null; | |
assert(ship->numrefs() == 2); | |
ship_alias = ship_alias2; | |
assert(ship->numrefs() == 1); | |
try { | |
(*ship_alias).numrefs(); | |
assert(0); | |
} catch (const char *e) { | |
cout << "dereferencing a null smartpointer throw as expected" << endl; | |
} | |
try { | |
ship_alias->numrefs(); | |
assert(0); | |
} catch (const char *e) { | |
cout << "dereferencing a null smartpointer throw as expected" << endl; | |
} | |
LOG("-- } TEST5"); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef __SMARTPOINTER_H__ | |
#define __SMARTPOINTER_H__ | |
#include <iostream> | |
#include <vector> | |
#include <typeinfo> | |
#include <string> | |
using std::vector; | |
using std::cout; | |
using std::endl; | |
using std::string; | |
#ifdef DEBUG | |
#define IS_DEBUG 1 | |
#else | |
#define IS_DEBUG 0 | |
#endif | |
#define LOG(x) if (IS_DEBUG) { cout << x << endl; } | |
#define TYPEDLOG(x) if (IS_DEBUG) { cout << typeid(*this).name() << "\t" << x << endl; } | |
const int null = 0; | |
template <class T> class smartpointer; | |
template <class T> | |
class smart { | |
friend class smartpointer<T>; | |
private: | |
typedef vector<smartpointer<T>*> ptrs_t; | |
ptrs_t ptrs; | |
public: | |
typedef smartpointer<T> ptr; | |
smart() { | |
TYPEDLOG("new"); | |
} | |
virtual ~smart() { | |
TYPEDLOG("delete"); | |
for (typename ptrs_t::iterator it = this->ptrs.begin(); it < this->ptrs.end(); ++it) { | |
TYPEDLOG("nullifying pointer"); | |
(*it)->wrapped = null; | |
} | |
} | |
unsigned int numrefs() { | |
return this->ptrs.size(); | |
} | |
}; | |
template <class T> | |
class smartpointer { | |
friend class smart<T>; | |
public: // for assertions in demo.cpp | |
T* wrapped; | |
public: | |
smartpointer(T* wrapped) : wrapped(wrapped) { | |
// TYPEDLOG("new"); | |
this->point(); | |
} | |
smartpointer(const smartpointer& other) : wrapped(other.wrapped){ | |
// TYPEDLOG("new"); | |
this->point(); | |
} | |
virtual ~smartpointer() { | |
TYPEDLOG("delete"); | |
this->clear(); | |
} | |
T* operator ->() const { | |
if (this->wrapped == null) | |
throw "Empty smartpointer"; | |
return this->wrapped; | |
} | |
T& operator *() const { | |
return *(this->operator->()); | |
} | |
operator T*() const { | |
return this->wrapped; | |
} | |
void clear() { | |
if (this->wrapped) | |
this->unpoint(); | |
} | |
smartpointer& operator= (T* ptr) { | |
if (ptr != this->wrapped) { | |
this->clear(); | |
if (ptr != null) { | |
this->wrapped = ptr; | |
this->point(); | |
} | |
} | |
return *this; | |
} | |
smartpointer& operator= (const smartpointer &other) { | |
return this->operator= (other.wrapped); | |
} | |
private: | |
void point() { | |
this->wrapped->ptrs.push_back(this); | |
} | |
void unpoint() { | |
smart<T>* ptr = this->wrapped; | |
int found = 0; | |
for (typename smart<T>::ptrs_t::iterator it = ptr->ptrs.begin(); | |
it < ptr->ptrs.end(); | |
++it) | |
{ | |
if (*it == this) { | |
ptr->ptrs.erase(it); | |
found = 1; | |
break; | |
} | |
} | |
assert(found); | |
if (ptr->ptrs.empty()) { | |
TYPEDLOG("auto-deleting"); | |
delete ptr; | |
} else { | |
TYPEDLOG("only forgetting"); | |
} | |
// C++ doesn't automatically null out the pointer | |
this->wrapped = null; | |
} | |
}; | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment