Skip to content

Instantly share code, notes, and snippets.

@aragaer
Created May 7, 2010 14:35
Show Gist options
  • Save aragaer/393493 to your computer and use it in GitHub Desktop.
Save aragaer/393493 to your computer and use it in GitHub Desktop.
smart pointers
#include "sptest.h"
#include <stdio.h>
class test {
public:
test() {
printf("Test constructor\n");
field = new char[20];
is_deleted = false;
}
~test() {
printf("Test destructor\n");
if (!is_deleted) // If you see the warning, something goes wrong
printf("Test was not cleaned up properly!\n");
delete field;
}
void hello() {
printf("Hello, test\n");
}
void del() {
is_deleted = true;
}
char *field;
bool is_deleted;
};
typedef Csptr<test> sp_test;
template <> void Csptr<test>::Cwrap::Cleanup() {
if (!m_value)
return;
m_value->del();
delete m_value;
}
// Typedef and cleanup using a macro. Should be expanded like this:
// typedef Csptr<int> spint;
// template <> void Csptr<int>::Cwrap::Cleanup() {
// // Nothing to do
// printf("Int smartptr cleanup!\n");
// }
SMARTPTR_CLEANUP_BEGIN(spint, int)
// Nothing to do
printf("Int smartptr cleanup!\n");
SMARTPTR_CLEANUP_END
template <> bool Csptr<int>::IsValid() {
printf("Something checks if the pointer is valid at all\n");
return m_wrap != NULL;
}
test *make_test() {
return new test();
}
sp_test make_sptest() {
return sp_test(*make_test());
}
int a = 15;
int main(int argc, char *argv[]) {
sp_test spt(*make_test());
Csptr<test> spt2; // Same as "sp_test spt2;"
sp_test spt3(make_sptest());
Csptr<int> spint, spint2(a);
// Csptr<char> spchar; // Won't compile since there's no cleanup for char defined
spt->hello();
spt2->hello();
spt3->hello();
printf("spt is %svalid\n", spt.IsValid() ? "" : "in");
printf("spt2 is %svalid\n", spt2.IsValid() ? "" : "in");
printf("spint is %svalid\n", spint.IsValid() ? "" : "in");
printf("spint2 is %svalid\n", spint2.IsValid() ? "" : "in");
spt3 = NULL;
spt3 = spt;
spt3.Unlink();
spt2 = spt;
spt2->hello();
printf("woof\n");
return 0;
}
#include <stdio.h>
template <typename T>
class Csptr {
class Cwrap { // Internal wrapper for data, which counts references to itself
//////////////////////////////////////////////////////////////////////////
/// @brief Конструктор
//////////////////////////////////////////////////////////////////////////
Cwrap(T *value) : m_value(value), m_ref(0) { }
//////////////////////////////////////////////////////////////////////////
/// @brief Деструктор
//////////////////////////////////////////////////////////////////////////
~Cwrap() { }
//////////////////////////////////////////////////////////////////////////
/// @brief Увеличить счетчик ссылок
//////////////////////////////////////////////////////////////////////////
void AddRef() {
m_ref++;
}
//////////////////////////////////////////////////////////////////////////
/// @brief Уменьшить счетчик ссылок
//////////////////////////////////////////////////////////////////////////
void Release() {
if (--m_ref == 0) {
Cleanup();
delete this;
}
}
//////////////////////////////////////////////////////////////////////////
/// @brief Доступ к содержимому
//////////////////////////////////////////////////////////////////////////
T *value() {
return m_value;
}
//////////////////////////////////////////////////////////////////////////
/// @brief Метод очистки хэндла. Должен быть определен для каждой специализации
//////////////////////////////////////////////////////////////////////////
virtual void Cleanup(); // Cleanup function. Must be defined for every used specialization
T *m_value;
int m_ref;
friend class Csptr;
};
public:
//////////////////////////////////////////////////////////////////////////
/// @brief Пустой конструктор
//////////////////////////////////////////////////////////////////////////
Csptr() : m_wrap(NULL) {}
//////////////////////////////////////////////////////////////////////////
/// @brief Конструктор копирования
//////////////////////////////////////////////////////////////////////////
Csptr(const Csptr &rval) { // Doesn't work without 'const'
m_wrap = rval.m_wrap;
m_wrap->AddRef();
#ifdef _DEBUG
printf("Smart pointer created from copy\n");
#endif
}
//////////////////////////////////////////////////////////////////////////
/// @brief Конструктор с инициализацией
//////////////////////////////////////////////////////////////////////////
Csptr(T &val) {
m_wrap = new Cwrap(&val);
m_wrap->AddRef();
#ifdef _DEBUG
printf("Smart pointer created\n");
#endif
}
//////////////////////////////////////////////////////////////////////////
/// @brief Деструктор
//////////////////////////////////////////////////////////////////////////
~Csptr() {
if (m_wrap)
m_wrap->Release();
#ifdef _DEBUG
else
printf("Non-initialized ");
printf("Smart pointer destroyed\n");
#endif
m_wrap = NULL;
}
/////////////////////////////////////////////////////////////////////////
/// @brief Разыменовать умный указатель. Для неинициализированных указателей вернет NULL
//////////////////////////////////////////////////////////////////////////
const T &operator * () const {
if (m_wrap == NULL) {
printf("Dereferencing null pointer!\n"); // Handle the error!
return NULL;
}
return *m_wrap->value();
}
//////////////////////////////////////////////////////////////////////////
/// @brief Разыменовать умный указатель. Для неинициализированных указателей вернет NULL
//////////////////////////////////////////////////////////////////////////
T *const operator -> () const {
if (m_wrap == NULL) {
printf("Dereferencing null pointer!\n"); // Handle the error!
return NULL;
}
return m_wrap->value();
}
//////////////////////////////////////////////////////////////////////////
/// @brief Оператор копирования умного указателя
//////////////////////////////////////////////////////////////////////////
Csptr &operator = (const Csptr &rval) {
if (m_wrap)
m_wrap->Release();
m_wrap = rval.m_wrap;
m_wrap->AddRef();
return *this;
}
//////////////////////////////////////////////////////////////////////////
/// @brief Оператор копирования умного указателя из обычного
//////////////////////////////////////////////////////////////////////////
Csptr &operator = (T *rval) {
if (m_wrap)
m_wrap->Release();
m_wrap = new Cwrap(rval);
m_wrap->AddRef();
return *this;
}
//////////////////////////////////////////////////////////////////////////
/// @brief make the pointer invalid, removing reference to object
//////////////////////////////////////////////////////////////////////////
void Unlink() {
if (m_wrap)
m_wrap->Release();
m_wrap = NULL;
}
//////////////////////////////////////////////////////////////////////////
/// @brief Returns whether the smart pointer is valid
//////////////////////////////////////////////////////////////////////////
bool IsValid() {
return m_wrap != NULL;
}
protected:
Cwrap *m_wrap;
};
// These macro definitions should wrap the cleanup definition.
// Wrapped value can be accessed as m_value
//////////////////////////////////////////////////////////////////////////
/// @brief Макрос начала объявления специализации умного указателя
//////////////////////////////////////////////////////////////////////////
#define SMARTPTR_CLEANUP_BEGIN(name, type) typedef Csptr<type> name; \
template <> void Csptr<type>::Cwrap::Cleanup() {
//////////////////////////////////////////////////////////////////////////
/// @brief Макрос окончания объявления специализации умного указателя
//////////////////////////////////////////////////////////////////////////
#define SMARTPTR_CLEANUP_END }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment