Skip to content

Instantly share code, notes, and snippets.

@aperezdc
Created November 1, 2013 15:53
Show Gist options
  • Save aperezdc/7267472 to your computer and use it in GitHub Desktop.
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.
/*
* 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