|
// Simple scope object to keep track and deallocate dynamic objects when leaving scope
// Article url: http://www.codeproject.com/Articles/468126/Local-NEW-or-Automatic-heap-cleanup-when-leaving-s
//
// Example: { Scope local; A* a=new(local) A(); }
// We left scope. Object "a" will be destroyed along with associated "local"scope object
//
// Author : Ladislav Nevery
#ifndef SCOPE_H
#define SCOPE_H
#ifdef __cplusplus
#ifdef WIN32
struct Lock : CRITICAL_SECTION { // we separated critical section to keep code portable
Lock() { InitializeCriticalSection(this); }
~Lock() { DeleteCriticalSection(this); }
void lock() { EnterCriticalSection(this); }
void unlock() { LeaveCriticalSection(this); }
};
#endif//WIN32
struct Scope { // This is non thread safe version for speed in local scope. From threads use thread safe TScope variant defined below
struct Obj { virtual ~Obj() {} };
Obj** pointer; int pointers; int capacity; char* is_obj; Lock* lock;
Scope(int Capacity=10) : pointer(0) , pointers(0), capacity(Capacity), is_obj(0) , lock(0){}
~Scope()
{
for(int i=pointers-1;i>=0;i--) {
if(pointer[i]) {
if(is_obj[i]) pointer[i]->~Obj(); // if what we stored is pointer to object call it's destructor first
free(pointer[i]);
}
}
free(pointer);
free(is_obj);
if(lock) delete lock;
}
void add(void* Pointer, int Is_obj)
{
if(lock) lock->lock();
if( capacity < pointers+1 || !pointer ) {
capacity = capacity+capacity>>1;
pointer = (Obj**)realloc(pointer, capacity * sizeof(Obj*) );
is_obj = (char*)realloc(is_obj, capacity * sizeof(char) );
}
pointer[pointers] = (Scope::Obj*)Pointer;
is_obj[pointers] = Is_obj;
pointers++;
if(lock) lock->unlock();
}
void del(void* Pointer)
{
if(lock) lock->lock();
for(int i=0;i<pointers;i++) {
if( pointer[i]==Pointer) {
pointer[i]=0;
break;
}
}
if(lock) lock->unlock();
}
};
// TScope is hread safe version of scope it is defined as separate type since it's slower
struct TScope : public Scope {
TScope(int Capacity=1000) : Scope(Capacity) {
lock=new Lock();
}
};
// scoped versions of object oriented memory functions memory of whose we release by calling delete
// which in turn calls their virtual destructors followed by internal call of standard free() when leaving scope
inline void * __cdecl operator new(unsigned int size,Scope& scope)
{
void *pointer = malloc(size);
scope.add(pointer,true);
return(pointer);
};
inline void __cdecl operator delete(void* pointer,Scope& scope)
{
scope.del(pointer);
((Scope::Obj*)pointer)->~Obj();
free(pointer);
}
// scoped versions of old C malloc based memory functions memory of whose we release by calling free() when leaving scope
inline char* strdup(Scope& scope, const char* text)
{
char* pointer = strdup(text);
scope.add(pointer,false);
return(pointer);
}
inline void* malloc(Scope& scope, size_t size)
{
void* pointer = malloc(size);
scope.add(pointer,false);
return(pointer);
}
inline void* calloc(Scope& scope, size_t size, size_t cnt)
{
void* pointer = calloc(size,cnt);
scope.add(pointer,false);
return(pointer);
}
inline void free(Scope& scope, void* pointer)
{
scope.del(pointer);
free(pointer);
}
#else // pure C language version of Scope
#ifdef WIN32
void* lock_create() {
void* lock=calloc(sizeof(CRITICAL_SECTION),1);
InitializeCriticalSection((CRITICAL_SECTION*)lock);
return lock;
}
void lock_destroy(void* lock) {
DeleteCriticalSection((CRITICAL_SECTION*)lock);
free(lock);
}
void Lock (void* lock) { EnterCriticalSection((CRITICAL_SECTION*)lock); }
void Unlock(void* lock) { LeaveCriticalSection((CRITICAL_SECTION*)lock); }
#endif//WIN32
typedef struct Scope_ { // This is non thread safe version for speed in local scope. From threads use thread safe TScope variant defined below
struct Scope* prev; void* pointer; void* lock;
} Scope;
Scope* create_scope(int thread_safe) {
Scope* scope=(Scope*)calloc(sizeof(Scope),1);
if(thread_safe) scope->lock=lock_create();
return scope;
}
void destroy_scope(Scope* scope) {
if(scope->pointer) free(scope->pointer);
destroy_scope(scope->prev);
if(scope->lock) { lock_destroy(scope->lock); }
}
void scope_add(Scope* scope,void* pointer)
{
if(scope->lock) Lock(scope->lock);
if(scope->pointer) { // make copy of current pointer and his type as a child
Scope* Prev=(Scope*)calloc(sizeof(Scope),1);
Prev->prev=scope->prev;
Prev->pointer=scope->pointer;
Prev->lock=scope->lock;
scope->prev=Prev;
}
scope->pointer=pointer;
if(scope->lock) Unlock(scope->lock);
}
void scope_del(Scope* scope,void* pointer)
{
Scope* s;
if(scope->lock) Lock(scope->lock);
for(s=scope; s; s=s->prev) {
if(s->pointer==pointer) s->pointer=0;
}
if(scope->lock) Unlock(scope->lock);
}
char* strdup_(Scope* scope, const char* text)
{
char* pointer = strdup(text);
scope_add(scope,pointer);
return(pointer);
}
void* malloc_(Scope* scope, size_t size)
{
void* pointer = malloc(size);
scope_add(scope,pointer);
return(pointer);
}
void* calloc_(Scope* scope, size_t size, size_t cnt)
{
void* pointer = calloc(size,cnt);
scope_add(scope,pointer);
return(pointer);
}
void free_(Scope* scope, void* pointer)
{
scope_del(scope,pointer);
free(pointer);
}
#endif // ! __cplusplus = end of C version
#endif //SCOPE_H
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.