Created
November 1, 2013 15:53
-
-
Save aperezdc/7267472 to your computer and use it in GitHub Desktop.
Custom allocation in C++ for arrays without using the built-in new[] and delete[] operators.
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
/* | |
* array-custom-allocation.cc | |
* Copyright (C) 2013 Adrian Perez <[email protected]> | |
* | |
* Distributed under terms of the MIT license. | |
*/ | |
#include <cstdio> | |
#include <cstdlib> | |
#include <cstdarg> | |
#include <cstring> | |
#include <new> | |
static void | |
__trace(const char* func, const char* fmt, ...) | |
{ | |
va_list args; | |
va_start(args, fmt); | |
fprintf(stderr, "%s", func); | |
if (fmt) { | |
fprintf(stderr, ": "); | |
vfprintf(stderr, fmt, args); | |
} | |
fprintf(stderr, "\n"); | |
va_end(args); | |
} | |
static inline void | |
__trace(const char* func) | |
{ | |
__trace(func, static_cast<const char*>(0)); | |
} | |
#define TRACE(...) __trace(__PRETTY_FUNCTION__, ##__VA_ARGS__) | |
class Alloc { | |
public: | |
void* New(size_t size) { | |
void* p = malloc(size); | |
TRACE("size = %lu, p = %p", static_cast<unsigned long>(size), p); | |
return p; | |
} | |
void Delete(void* p) { | |
TRACE("p = %p", p); | |
free(p); | |
} | |
}; | |
class Item { | |
public: | |
Item(): d(20.0), i(42) { | |
TRACE(); | |
} | |
~Item() { | |
TRACE(); | |
} | |
void* operator new(size_t size, Alloc alloc) { | |
void* p = alloc.New(size); | |
TRACE("size = %lu, p = %p", static_cast<unsigned long>(size), p); | |
return p; | |
} | |
void operator delete(void* p, Alloc alloc) { | |
TRACE("p = %p", p); | |
alloc.Delete(p); | |
} | |
// Some data | |
double d; | |
int i; | |
private: | |
// Disallow operators, forcing to use NewArray/Delete[Array] | |
void* operator new[](size_t size, Alloc alloc) { abort(); return 0; } | |
void operator delete(void* p) { abort(); } | |
void operator delete[](void* p) { abort(); } | |
void operator delete[](void* p, Alloc alloc) { abort(); } | |
}; | |
template<typename T> | |
void Delete(Alloc alloc, T* p) { | |
TRACE("p = %p", p); | |
if (p != 0) { | |
p->~T(); | |
alloc.Delete(p); | |
} | |
} | |
template<typename T> | |
T* NewArray(Alloc alloc, size_t nitems) | |
{ | |
// Overallocate to have extra space for a size_t | |
size_t* p = reinterpret_cast<size_t*> | |
(alloc.New(sizeof(T) * nitems + sizeof(size_t))); | |
TRACE("sizeof(T) = %lu, nitems = %lu, size = %lu, p = %p", | |
static_cast<unsigned long>(sizeof(T)), | |
static_cast<unsigned long>(nitems), | |
static_cast<unsigned long>(sizeof(T) * nitems + sizeof(size_t)), | |
p + 1); | |
// Store number of items in the prefix space | |
*p = nitems; | |
// Run constructors | |
for (T* tp = reinterpret_cast<T*>(p + 1); nitems--; tp++) { | |
::new(reinterpret_cast<void*>(tp)) T; // placement-new | |
} | |
// Return pointer to the first item after the number of items | |
return reinterpret_cast<T*>(p + 1); | |
} | |
template<typename T> | |
void DeleteArray(Alloc alloc, T* p) | |
{ | |
TRACE("p = %p", p); | |
if (p != 0) { | |
// Get number of items from the prefix space | |
size_t nitems = *(reinterpret_cast<size_t*>(p) - 1); | |
// Run destructors | |
for (T* tp = p; nitems--; tp++) { | |
tp->~T(); | |
} | |
alloc.Delete(reinterpret_cast<size_t*>(p) - 1); | |
} | |
} | |
template<> | |
int* NewArray(Alloc alloc, size_t nitems) | |
{ | |
TRACE("nitems = %lu [specialized: int]", | |
static_cast<unsigned long>(nitems)); | |
int* p = reinterpret_cast<int*>(alloc.New(sizeof(int) * nitems)); | |
memset(p, 0x00, sizeof(int) * nitems); | |
return p; | |
} | |
template<> | |
void DeleteArray(Alloc alloc, int* p) | |
{ | |
TRACE("p = %p [specialized: int]", p); | |
alloc.Delete(p); | |
} | |
int main() | |
{ | |
Alloc alloc; | |
TRACE("---- Single item"); | |
Item *item = new(alloc) Item; | |
Delete(alloc, item); | |
TRACE("---- Array with 1 item"); | |
item = NewArray<Item>(alloc, 1); | |
DeleteArray(alloc, item); | |
TRACE("---- Array with 2 items"); | |
item = NewArray<Item>(alloc, 2); | |
DeleteArray(alloc, item); | |
TRACE("---- Array with 3 chars"); | |
char* charp = NewArray<char>(alloc, 3); | |
DeleteArray(alloc, charp); | |
TRACE("---- Array with 7 ints (specialized)"); | |
int* intp = NewArray<int>(alloc, 7); | |
DeleteArray(alloc, intp); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment