473,769 Members | 5,869 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

a simple type-based C++ region allocator...

Here is the initial crude implmentation which compiles under Comeau with no
warnings:
_______________ _______________ _______________ _______________ _______
#include <cassert>
#include <cstdlib>
#include <new>
#include <list>
template<typena me T, std::size_t BUFDEPTH = 1024>
class region_allocato r {
struct region {
T m_buf[BUFDEPTH];
std::size_t m_idx;
void ctor() {
m_idx = 0;
}
void dtor() {
for (std::size_t i = 0; i < m_idx; ++i) {
m_buf[i].~T();
}
}
void* allocate() {
std::size_t const idx = m_idx;
if (idx + 1 BUFDEPTH) {
return NULL;
}
return (void*)&m_buf[idx];
}
void commit() {
++m_idx;
}
void flush() {
dtor();
ctor();
}
};
std::list<regio n*m_regions;
struct allocation {
region* m_region;
void* m_mem;
};
region* prv_expand(){
region* r = (region*)std::m alloc(sizeof(*r ));
if (! r) {
throw std::bad_alloc( );
};
r->ctor();
m_regions.push_ front(r);
return r;
}
inline void prv_allocate(al location* const a) {
typename std::list<regio n*>::iterator i;
for (i = m_regions.begin (); i != m_regions.end() ; ++i) {
a->m_mem = (*i)->allocate();
if (a->m_mem) {
a->m_region = (*i);
return;
}
}
a->m_region = prv_expand();
a->m_mem = a->m_region->allocate();
assert(a->m_mem);
}
#define REGION_PRV_ALLO CATE(mp_params) \
allocation a; \
prv_allocate(&a ); \
T* const obj = new (a.m_mem) T mp_params; \
a.m_region->commit(); \
return obj
public:
struct flush_guard {
region_allocato r& m_ralloc;

public:
flush_guard(reg ion_allocator& ralloc) : m_ralloc(ralloc ) {
m_ralloc.flush( );
}

~flush_guard() {
m_ralloc.flush( );
}
};
region_allocato r() {
prv_expand();
}
~region_allocat or() {
flush();
std::free(m_reg ions.front());
m_regions.pop_f ront();
}
void flush() {
std::size_t const depth = m_regions.size( );
for (std::size_t i = 1; i < depth; ++i) {
region* const r = m_regions.back( );
r->dtor();
std::free(r);
m_regions.pop_b ack();
}
m_regions.front ()->flush();
}
inline T* allocate() {
REGION_PRV_ALLO CATE(());
}
template<typena me P1>
inline T* allocate(P1 p1) {
REGION_PRV_ALLO CATE((p1));
}
template<typena me P1, typename P2>
inline T* allocate(P1 p1, P2 p2) {
REGION_PRV_ALLO CATE((p1, p2));
}
template<typena me P1, typename P2, typename P3>
inline T* allocate(P1 p1, P2 p2, P3 p3) {
REGION_PRV_ALLO CATE((p1, p2, p3));
}
// [and on and on for more params...];
};


/* Usage Example
_______________ _______________ _______________ _______________ __*/
#include <cstdio>
#include <string>
class foo {
unsigned const m_id;

public:
foo(unsigned const id) : m_id(id) {
std::printf("(% p)->foo::foo(%u)\n ", (void*)this, id);
}
~foo() {
std::printf("(% p)->foo::~foo() - %u\n", (void*)this, m_id);
}
};
class foo2 {
unsigned const m_id;
std::string const m_name;

public:
foo2(unsigned const id, std::string const name)
: m_id(id), m_name(name) {
std::printf("(% p)->foo2::foo2(% u, %s)\n",
(void*)this, id, name.c_str());
}
~foo2() {
std::printf("(% p)->foo2::~foo2( ) - %u, %s\n",
(void*)this, m_id, m_name.c_str()) ;
}
};
struct node {
node* m_next;

node(node* next) : m_next(next) {
std::printf("(% p)->node::node(%p) \n",
(void*)this, (void*)next);
}

~node() {
std::printf("(% p)->node::~node(%p )\n",
(void*)this, (void*)m_next);
}
};
int main(void) {
{
region_allocato r<foo, 2foo_alloc;

{
region_allocato r<foo, 2>::flush_guar d fguard(foo_allo c);
foo* f1 = foo_alloc.alloc ate(1);
foo* f2 = foo_alloc.alloc ate(2);
foo* f3 = foo_alloc.alloc ate(3);
foo* f4 = foo_alloc.alloc ate(4);
}

foo* f1 = foo_alloc.alloc ate(5);
foo* f2 = foo_alloc.alloc ate(6);
foo* f3 = foo_alloc.alloc ate(7);
foo* f4 = foo_alloc.alloc ate(8);

{
region_allocato r<foo2foo2_allo c;
foo2* f2_1 = foo2_alloc.allo cate(123, "Chris");
foo2* f2_2 = foo2_alloc.allo cate(456, "John");
foo2* f2_3 = foo2_alloc.allo cate(789, "Amy");
foo2* f2_4 = foo2_alloc.allo cate(777, "Kim");
foo2* f2_5 = foo2_alloc.allo cate(999, "Jane");
}
{
region_allocato r<unsigned, 64int_alloc;

unsigned* a1 = int_alloc.alloc ate(1);
unsigned* a2 = int_alloc.alloc ate(2);
unsigned* a3 = int_alloc.alloc ate(3);
unsigned* a4 = int_alloc.alloc ate();

*a4 = 123456789;

std::printf("%u - %u - %u - %u\n", *a1, *a2, *a3, *a4);
}
}

{
region_allocato r<nodenode_allo c;
node* head = NULL; // linked-list

// fill
for (unsigned i = 0; i < 512; ++i) {
node* n = node_alloc.allo cate(head);
head = n;
}

// empty list
head = NULL;
node_alloc.flus h();
// refill
for (unsigned i = 0; i < 2048; ++i) {
node* n = node_alloc.allo cate(head);
head = n;
}
}

return 0;
}
_______________ _______________ _______________ _______________ _______


Notice how there are no explicit calls to a per-object deallocation
function? The `region_allocat or<T, ...>::flush_gua rd' object uses RAII to
automatically invoke the `region_allocat or<T, ...>::flush()' procedure which
calls the dtor of all contained objects and automatically frees excess
region memory. One nice thing is that it allows one to pass variable number
of arguments to the objects ctor.

Also, please take notice of how I can create a linked-list, and simple call
`flush()' to automatically destroy all of its nodes _without_ explicitly
traversing it. IMVHO, that ability can come in handy.


Well, what do you think of the initial design? Is it crap? How would you
improve it?


Thanks for all of your time! I really do appreciate it.
:^)
Nov 18 '08 #1
8 3167

"Chris M. Thomasson" <no@spam.invali dwrote in message
news:gf******** **@aioe.org...
Here is the initial crude implmentation which compiles under Comeau with
no
warnings:
_______________ _______________ _______________ _______________ _______
#include <cassert>
#include <cstdlib>
#include <new>
#include <list>
template<typena me T, std::size_t BUFDEPTH = 1024>
class region_allocato r {
struct region {
T m_buf[BUFDEPTH];
std::size_t m_idx;
void ctor() {
m_idx = 0;
}
void dtor() {
for (std::size_t i = 0; i < m_idx; ++i) {
m_buf[i].~T();
}
}
void* allocate() {
std::size_t const idx = m_idx;
if (idx + 1 BUFDEPTH) {
return NULL;
}
return (void*)&m_buf[idx];
}
void commit() {
++m_idx;
}
void flush() {
dtor();
ctor();
}
};
std::list<regio n*m_regions;
struct allocation {
region* m_region;
void* m_mem;
};
region* prv_expand(){
region* r = (region*)std::m alloc(sizeof(*r ));
if (! r) {
throw std::bad_alloc( );
};
r->ctor();
m_regions.push_ front(r);
return r;
}
inline void prv_allocate(al location* const a) {
typename std::list<regio n*>::iterator i;
for (i = m_regions.begin (); i != m_regions.end() ; ++i) {
a->m_mem = (*i)->allocate();
if (a->m_mem) {
a->m_region = (*i);
return;
}
}
a->m_region = prv_expand();
a->m_mem = a->m_region->allocate();
assert(a->m_mem);
}
#define REGION_PRV_ALLO CATE(mp_params) \
allocation a; \
prv_allocate(&a ); \
T* const obj = new (a.m_mem) T mp_params; \
a.m_region->commit(); \
return obj
public:
struct flush_guard {
region_allocato r& m_ralloc;

public:
flush_guard(reg ion_allocator& ralloc) : m_ralloc(ralloc ) {
m_ralloc.flush( );
}
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^
ARGHH23$#@$@#!! !!
DAMNIT!!!!
Okay, I make error here... The call to flush should NOT be in the darn ctor
of the `flush_guard' object!
Sorry about that non-sense!
[...]

Here is full fixed code:
_______________ _______________ _______________ _______________ __________
#include <cassert>
#include <cstdlib>
#include <new>
#include <list>
template<typena me T, std::size_t BUFDEPTH = 1024>
class region_allocato r {
struct region {
T m_buf[BUFDEPTH];
std::size_t m_idx;
void ctor() {
m_idx = 0;
}
void dtor() {
for (std::size_t i = 0; i < m_idx; ++i) {
m_buf[i].~T();
}
}
void* allocate() {
std::size_t const idx = m_idx;
if (idx + 1 BUFDEPTH) {
return NULL;
}
return (void*)&m_buf[idx];
}
void commit() {
++m_idx;
}
void flush() {
dtor();
ctor();
}
};
std::list<regio n*m_regions;
struct allocation {
region* m_region;
void* m_mem;
};
region* prv_expand(){
region* r = (region*)std::m alloc(sizeof(*r ));
if (! r) {
throw std::bad_alloc( );
};
r->ctor();
m_regions.push_ front(r);
return r;
}
inline void prv_allocate(al location* const a) {
typename std::list<regio n*>::iterator i;
for (i = m_regions.begin (); i != m_regions.end() ; ++i) {
a->m_mem = (*i)->allocate();
if (a->m_mem) {
a->m_region = (*i);
return;
}
}
a->m_region = prv_expand();
a->m_mem = a->m_region->allocate();
assert(a->m_mem);
}
#define REGION_PRV_ALLO CATE(mp_params) \
allocation a; \
prv_allocate(&a ); \
T* const obj = new (a.m_mem) T mp_params; \
a.m_region->commit(); \
return obj
public:
struct flush_guard {
region_allocato r& m_ralloc;

public:
flush_guard(reg ion_allocator& ralloc) : m_ralloc(ralloc ) {

}

~flush_guard() {
m_ralloc.flush( );
}
};
region_allocato r() {
prv_expand();
}
~region_allocat or() {
flush();
std::free(m_reg ions.front());
m_regions.pop_f ront();
}
void flush() {
std::size_t const depth = m_regions.size( );
for (std::size_t i = 1; i < depth; ++i) {
region* const r = m_regions.back( );
r->dtor();
std::free(r);
m_regions.pop_b ack();
}
m_regions.front ()->flush();
}
inline T* allocate() {
REGION_PRV_ALLO CATE(());
}
template<typena me P1>
inline T* allocate(P1 p1) {
REGION_PRV_ALLO CATE((p1));
}
template<typena me P1, typename P2>
inline T* allocate(P1 p1, P2 p2) {
REGION_PRV_ALLO CATE((p1, p2));
}
template<typena me P1, typename P2, typename P3>
inline T* allocate(P1 p1, P2 p2, P3 p3) {
REGION_PRV_ALLO CATE((p1, p2, p3));
}
// [and on and on for more params...];
};


/* Usage Example
_______________ _______________ _______________ _______________ __*/
#include <cstdio>
#include <string>
class foo {
unsigned const m_id;

public:
foo(unsigned const id) : m_id(id) {
std::printf("(% p)->foo::foo(%u)\n ", (void*)this, id);
}
~foo() {
std::printf("(% p)->foo::~foo() - %u\n", (void*)this, m_id);
}
};
class foo2 {
unsigned const m_id;
std::string const m_name;

public:
foo2(unsigned const id, std::string const name)
: m_id(id), m_name(name) {
std::printf("(% p)->foo2::foo2(% u, %s)\n",
(void*)this, id, name.c_str());
}
~foo2() {
std::printf("(% p)->foo2::~foo2( ) - %u, %s\n",
(void*)this, m_id, m_name.c_str()) ;
}
};
struct node {
node* m_next;

node(node* next) : m_next(next) {
std::printf("(% p)->node::node(%p) \n",
(void*)this, (void*)next);
}

~node() {
std::printf("(% p)->node::~node(%p )\n",
(void*)this, (void*)m_next);
}
};
int main(void) {
{
region_allocato r<foo, 2foo_alloc;

{
region_allocato r<foo, 2>::flush_guar d fguard(foo_allo c);
foo* f1 = foo_alloc.alloc ate(1);
foo* f2 = foo_alloc.alloc ate(2);
foo* f3 = foo_alloc.alloc ate(3);
foo* f4 = foo_alloc.alloc ate(4);
}

foo* f1 = foo_alloc.alloc ate(5);
foo* f2 = foo_alloc.alloc ate(6);
foo* f3 = foo_alloc.alloc ate(7);
foo* f4 = foo_alloc.alloc ate(8);

{
region_allocato r<foo2foo2_allo c;
foo2* f2_1 = foo2_alloc.allo cate(123, "Chris");
foo2* f2_2 = foo2_alloc.allo cate(456, "John");
foo2* f2_3 = foo2_alloc.allo cate(789, "Amy");
foo2* f2_4 = foo2_alloc.allo cate(777, "Kim");
foo2* f2_5 = foo2_alloc.allo cate(999, "Jane");
}
{
region_allocato r<unsigned, 64int_alloc;

unsigned* a1 = int_alloc.alloc ate(1);
unsigned* a2 = int_alloc.alloc ate(2);
unsigned* a3 = int_alloc.alloc ate(3);
unsigned* a4 = int_alloc.alloc ate();

*a4 = 123456789;

std::printf("%u - %u - %u - %u\n", *a1, *a2, *a3, *a4);
}
}

{
region_allocato r<nodenode_allo c;
node* head = NULL; // linked-list

// fill
for (unsigned i = 0; i < 512; ++i) {
node* n = node_alloc.allo cate(head);
head = n;
}

// empty list
head = NULL;
node_alloc.flus h();
// refill
for (unsigned i = 0; i < 2048; ++i) {
node* n = node_alloc.allo cate(head);
head = n;
}
}

return 0;
}
_______________ _______________ _______________ _______________ __________

Sorry about that stupid non-sense!
;^(....

Nov 18 '08 #2
I fix some nasty exception safety issues that exist in the initial version
by removing dependence on `std::list'. I implement a trivial intrusive
circular doubly linked-list instead. Every operation is guaranteed not to
throw. Also, it improves efficiency because regions are now nodes.
Therefore, nodes do not need to be separately allocated. This is one
advantage intrusive containers have over the STL. Anyway, here is the code:
_______________ _______________ _______________ _______________ __________
#include <cassert>
#include <cstdlib>
#include <new>


template<typena me T>
struct dlink {
dlink* m_next;
dlink* m_prev;
void ctor() {
m_next = m_prev = this;
}
private:
inline static void prv_insert(
dlink* n,
dlink* prev,
dlink* next
) throw() {
next->m_prev = n;
n->m_next = next;
n->m_prev = prev;
prev->m_next = n;
}
inline static void prv_remove(
dlink* prev,
dlink* next
) throw() {
next->m_prev = prev;
prev->m_next = next;
}
public:
inline void push_head(dlink * n) throw() {
prv_insert(n, this, m_next);
}
inline void push_tail(dlink * n) throw() {
prv_insert(n, m_prev, this);
}
inline void pop() throw() {
prv_remove(m_pr ev, m_next);
}
inline T* get() throw() {
return (T*)this;
}
};


template<typena me T, std::size_t BUFDEPTH = 1024>
class region_allocato r {
struct region : dlink<region{
T m_buf[BUFDEPTH];
std::size_t m_idx;
void ctor() {
m_idx = 0;
}
void dtor() {
for (std::size_t i = 0; i < m_idx; ++i) {
m_buf[i].~T();
}
}
void* allocate() {
std::size_t const idx = m_idx;
if (idx + 1 BUFDEPTH) {
return NULL;
}
return (void*)&m_buf[idx];
}
void commit() {
++m_idx;
}
void flush() {
dtor();
ctor();
}
};
dlink<regionm_r egions;
struct allocation {
region* m_region;
void* m_mem;
};
region* prv_expand(){
region* r = (region*)std::m alloc(sizeof(*r ));
if (! r) {
throw std::bad_alloc( );
};
r->ctor();
m_regions.push_ head(r);
return r;
}
inline void prv_allocate(al location& a) {
region* r = m_regions.m_nex t->get();
while (r != &m_regions) {
a.m_mem = r->allocate();
if (a.m_mem) {
a.m_region = r;
return;
}
r = r->m_next->get();
}
a.m_region = prv_expand();
a.m_mem = a.m_region->allocate();
}
#define REGION_PRV_ALLO CATE(mp_params) \
allocation a; \
prv_allocate(a) ; \
T* const obj = new (a.m_mem) T mp_params; \
a.m_region->commit(); \
return obj
public:
struct flush_guard {
region_allocato r& m_ralloc;

public:
flush_guard(reg ion_allocator& ralloc) : m_ralloc(ralloc ) {

}

~flush_guard() {
m_ralloc.flush( );
}
};
region_allocato r() {
m_regions.ctor( );
prv_expand();
}
~region_allocat or() {
flush();
std::free(m_reg ions.m_next->get());
}
void flush() {
region* r = m_regions.m_nex t->get();
if (r->m_next != &m_regions) {
r = r->m_next->get();
while (r != &m_regions) {
region* rn = r->m_next->get();
r->pop();
r->dtor();
std::free(r);
r = rn;
}
}
m_regions.m_nex t->get()->flush();
}
inline T* allocate() {
REGION_PRV_ALLO CATE(());
}
template<typena me P1>
inline T* allocate(P1 p1) {
REGION_PRV_ALLO CATE((p1));
}
template<typena me P1, typename P2>
inline T* allocate(P1 p1, P2 p2) {
REGION_PRV_ALLO CATE((p1, p2));
}
template<typena me P1, typename P2, typename P3>
inline T* allocate(P1 p1, P2 p2, P3 p3) {
REGION_PRV_ALLO CATE((p1, p2, p3));
}
// [and on and on for more params...];
};


/* Usage Example
_______________ _______________ _______________ _______________ __*/
#include <cstdio>
#include <string>
class foo {
unsigned const m_id;

public:
foo(unsigned const id) : m_id(id) {
std::printf("(% p)->foo::foo(%u)\n ", (void*)this, id);
}
~foo() {
std::printf("(% p)->foo::~foo() - %u\n", (void*)this, m_id);
}
};
class foo2 {
unsigned const m_id;
std::string const m_name;

public:
foo2(unsigned const id, std::string const name)
: m_id(id), m_name(name) {
std::printf("(% p)->foo2::foo2(% u, %s)\n",
(void*)this, id, name.c_str());
}
~foo2() {
std::printf("(% p)->foo2::~foo2( ) - %u, %s\n",
(void*)this, m_id, m_name.c_str()) ;
}
};
struct node {
node* m_next;

node(node* next) : m_next(next) {
std::printf("(% p)->node::node(%p) \n",
(void*)this, (void*)next);
}

~node() {
std::printf("(% p)->node::~node(%p )\n",
(void*)this, (void*)m_next);
}
};
int main() {
{
region_allocato r<foo, 2foo_alloc;

{
region_allocato r<foo, 2>::flush_guar d fguard(foo_allo c);
foo* f1 = foo_alloc.alloc ate(1);
foo* f2 = foo_alloc.alloc ate(2);
foo* f3 = foo_alloc.alloc ate(3);
foo* f4 = foo_alloc.alloc ate(4);
foo* f5 = foo_alloc.alloc ate(5);
foo* f6 = foo_alloc.alloc ate(6);
}

foo* f1 = foo_alloc.alloc ate(5);
foo* f2 = foo_alloc.alloc ate(6);
foo* f3 = foo_alloc.alloc ate(7);
foo* f4 = foo_alloc.alloc ate(8);

{
region_allocato r<foo2foo2_allo c;
foo2* f2_1 = foo2_alloc.allo cate(123, "Chris");
foo2* f2_2 = foo2_alloc.allo cate(456, "John");
foo2* f2_3 = foo2_alloc.allo cate(789, "Amy");
foo2* f2_4 = foo2_alloc.allo cate(777, "Kim");
foo2* f2_5 = foo2_alloc.allo cate(999, "Jane");
}
{
region_allocato r<unsigned, 64int_alloc;

unsigned* a1 = int_alloc.alloc ate(1);
unsigned* a2 = int_alloc.alloc ate(2);
unsigned* a3 = int_alloc.alloc ate(3);
unsigned* a4 = int_alloc.alloc ate();

*a4 = 123456789;

std::printf("%u - %u - %u - %u\n", *a1, *a2, *a3, *a4);
}
}

{
region_allocato r<node, 10node_alloc;
node* head = NULL; // linked-list

// fill
for (unsigned i = 0; i < 14; ++i) {
node* n = node_alloc.allo cate(head);
head = n;
}

// empty list
head = NULL;
node_alloc.flus h();
// refill
for (unsigned i = 0; i < 15; ++i) {
node* n = node_alloc.allo cate(head);
head = n;
}
}

return 0;
}
_______________ _______________ _______________ _______________ __________

Well, what do you think of it? IMVHO, I think it can be a fairly useful tool
indeed. How can I make any further improvements?

Thanks.

Nov 19 '08 #3
Chris M. Thomasson wrote:
Well, what do you think of it? IMVHO, I think it can be a fairly useful
tool indeed. How can I make any further improvements?
How do you deallocate (so that deallocated elements can be reused by
further allocations)?
Nov 19 '08 #4
"Juha Nieminen" <no****@thanks. invalidwrote in message
news:xW******** ******@read4.in et.fi...
Chris M. Thomasson wrote:
>Well, what do you think of it? IMVHO, I think it can be a fairly useful
tool indeed. How can I make any further improvements?

How do you deallocate (so that deallocated elements can be reused by
further allocations)?
Region allocation forbids one from deallocating individual objects; you can
only deallocate all previously allocated objects. The
`region_allocat or<...>::flush( )' procedure does just that. This is a major
limitation inherent in basically any region-based allocators. However, Emery
Berger has created a workaround which combines region and heap allocation
and named the algorithm "Reaps":
http://www.cs.umass.edu/~emery/pubs/...oopsla2002.pdf
You can free individual objects back to a reap. You can also free all
previously allocated objects in a reap in one shot.
IMVHO, region allocation has its place. It can help get rid of memory leaks,
and provides certain conveniences. For instance, you don't need to traverse
a custom collection just to delete all objects therein. Instead, you can set
the collection to an empty state, and flush its region and all of the dtors
for its previously contained objects will fire. Take the following into
account:
http://groups.google.com/group/comp....419704ab8c471d

http://groups.google.com/group/comp....3c3b7d353bd3d9
Here is how one could implement partitioned region allocation as shown in
the C pseudo-code contained within the latter link:
_______________ _______________ _______________ _______________ ___________
// [snip region allocator code]
/* Region Partition Usage Example
_______________ _______________ _______________ _______________ __*/
#include <cstdio>
template<typena me T, std::size_t BUFDEPTH = 1024>
class partition_alloc ator {
public:
typedef region_allocato r<T, BUFDEPTHpartiti on;
private:
struct node {
node* m_next;
partition m_partition;
};

region_allocato r<node, 1m_palloc;
node* m_partitions;
public:
partition_alloc ator() : m_partitions(NU LL) {}

partition* allocate() {
node* const n = m_palloc.alloca te();
n->m_next = m_partitions;
m_partitions = n;
return &n->m_partition;
}

void flush() {
node* n = m_partitions;
while (n) {
n->m_partition.fl ush();
n = n->m_next;
}
}
};
struct node {
node* m_next;

node(node* next) : m_next(next) {
std::printf("(% p)->node::node(%p) \n",
(void*)this, (void*)next);
}

~node() {
std::printf("(% p)->node::~node(%p )\n",
(void*)this, (void*)m_next);
}
};
int main(void) {
{
unsigned i, r;

partition_alloc ator<nodenpallo c;
partition_alloc ator<node>::par tition& l1alloc = *npalloc.alloca te();
partition_alloc ator<node>::par tition& l2alloc = *npalloc.alloca te();
partition_alloc ator<node>::par tition& l3alloc = *npalloc.alloca te();

node* list1 = NULL;
node* list2 = NULL;
node* list3 = NULL;

for (r = 0; r < 3; ++r) {
// fill list 1
std::puts("fill ing list 1...");
for (i = 0; i < 10; ++i) {
node* n = l1alloc.allocat e(list1);
list1 = n;
}

// fill list 2
std::puts("\n\n filling list 2...");
for (i = 0; i < 10; ++i) {
node* n = l2alloc.allocat e(list2);
list2 = n;
}

// fill list 3
std::puts("\n\n filling list 3...");
for (i = 0; i < 10; ++i) {
node* n = l3alloc.allocat e(list3);
list3 = n;
}

// destroy list 1 in a single shot
list1 = NULL;
std::puts("\n\n destroy list 1 in one call...");
l1alloc.flush() ;

// refill list 1
std::puts("\n\n refilling list 1...");
for (i = 0; i < 10; ++i) {
node* n = l1alloc.allocat e(list1);
list1 = n;
}

// destroy lists 1, 2 and 3 in a single shot
list1 = list2 = list3 = NULL;
std::puts("\n\n destroy list 1, 2 and 3 in one call...");
npalloc.flush() ;
}
}

return 0;
}
_______________ _______________ _______________ _______________ ___________


As you can see, each list has its own "slave" region_allocato r derived from
the "master" partition_alloc ator. You can destroy all the nodes for a given
list by simply flushing its region_allocato r. Or, you can destroy all the
nodes from all the lists by flushing the "master" partition_alloc ator. Do
you think this is useful at all? Humm...

Nov 19 '08 #5
Chris M. Thomasson wrote:
Region allocation forbids one from deallocating individual objects; you
can only deallocate all previously allocated objects.
Then what's the point? You can't substitute new/malloc with such a
thing. The whole idea is that you should be able to destroy and
deallocate objects.

If you never deallocate anything, you may as well just use a
deque-style data container as your allocator, always appending newly
allocated memory blocks at the end.
Nov 20 '08 #6
"Juha Nieminen" <no****@thanks. invalidwrote in message
news:oa******** ******@read4.in et.fi...
Chris M. Thomasson wrote:
>Region allocation forbids one from deallocating individual objects; you
can only deallocate all previously allocated objects.

Then what's the point?
Did you read the paper I linked to? It explains the benefits and caveats of
region allocation. Surely you must be familiar with this type of allocation
scheme. Its been around for a long time.

You can't substitute new/malloc with such a thing.
You can substitute new/malloc, however, you "generally" cannot substitute
delete/free. Region allocation API would look like:
new/malloc
delete_all/free_all
Here is a multi-threaded region allocator I did which is used by overloaded
global new/delete operators:
http://webpages.charter.net/appcore/...em_thread.html
I did this for fun. It still suffers from the same caveats. If you notice, a
call to delete simply decrements a counter, and destroys the owning region
when it hits zero.

The whole idea is that you should be able to destroy and
deallocate objects.
You can deallocate objects. Just all the objects at once.

If you never deallocate anything,
You can deallocate all objects in one shot. That's the point of region
allocation. Have you looked at my code and some of the example uses?

you may as well just use a
deque-style data container as your allocator, always appending newly
allocated memory blocks at the end.
I don't want to explicitly allocate memory for each individual object. I
want a slab of memory which can hold multiple objects. Have you looked at my
code yet? Please examine it. I build a region of raw memory which can hold a
number of objects. I call there ctors on demand, and only call the dtors of
all previously allocated objects when the user flushes the region.

Nov 20 '08 #7
Chris M. Thomasson wrote:
>You can't substitute new/malloc with such a thing.

You can substitute new/malloc, however, you "generally" cannot
substitute delete/free.
Which is precisely the reason why you can't substitute new/malloc with
such a thing: You can never free any object, unless you free all objects.
>you may as well just use a
deque-style data container as your allocator, always appending newly
allocated memory blocks at the end.

I don't want to explicitly allocate memory for each individual object. I
want a slab of memory which can hold multiple objects.
Which is exactly what I suggested above.
Nov 20 '08 #8
"Juha Nieminen" <no****@thanks. invalidwrote in message
news:aC******** *******@read4.i net.fi...
Chris M. Thomasson wrote:
>>You can't substitute new/malloc with such a thing.

You can substitute new/malloc, however, you "generally" cannot
substitute delete/free.

Which is precisely the reason why you can't substitute new/malloc with
such a thing: You can never free any object, unless you free all objects.
>>you may as well just use a
deque-style data container as your allocator, always appending newly
allocated memory blocks at the end.

I don't want to explicitly allocate memory for each individual object. I
want a slab of memory which can hold multiple objects.

Which is exactly what I suggested above.
Sorry for being so retarded, but how would a deque improve on my existing
design? Can you give me some examples? Thanks Juha.

Nov 20 '08 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
7113
by: mjcsfo | last post by:
I can't seem to find a reference nor any helpful threads on this topic. I've gotten the following error in two circumstances: 1. A complex type has nested within it another complex type, in the "Russian doll" style of schema design, where the nested type is local and anonymous (not a separate global type). 2. A complex type has nested within it a simple type which is derived through restriction with at least one facet, again nested,...
4
2661
by: scorpion | last post by:
I have a simple type like this: <xs:simpleType name="SizeType"> <xs:restriction base="xs:token"> <xs:enumeration value="small"/> <xs:enumeration value="medium"/> <xs:enumeration value="large"/> <xs:enumeration value="xlarge"/> </xs:restriction> </xs:simpleType>
7
1437
by: Bruce Duncan | last post by:
I know this should be simple...but for some reason my brain isn't working. I want my users to enter a the date in three seperate boxes. After the users enters in two digits for the month I want the cursor to move to the day textbox and so on.... I was using simple code...but onKeyPress occurs before the value changes...can anyone help me? my code:
6
2158
by: francisco lopez | last post by:
ok , first of all sorry if my english is not so good, I do my best. here is my problem: I don´t know much javascript so I wrote a very simple one to validate a form I have on my webpage. could you please have a look at the following script: ------------------------------------------------------------
1
9491
by: Derrick | last post by:
I have the below simple class - public class MyClass { protected string m_stName; protected string m_stCode; protected int m_iId; public MyClass() {}
2
1290
by: Mike D Sutton | last post by:
Please excuse the terribly 'newbie'ness of this question, unfortunately my C# is very rusty.. What I'm trying to do is write a simple interactive drawing application where a few lines can be moved around on the form. What I'm trying to do is in the MouseDown() event hit test each line point and when I find one, store a _reference_ to it. The MouseMove event then checks to see if this reference has been set, if so it will edit this point and...
19
2987
by: Dales | last post by:
I have a custom control that builds what we refer to as "Formlets" around some content in a page. These are basically content "wrapper" sections that are tables that have a colored header and provide an open TD with a DIV in it for the content of this formlet. (The DIV is for DHTML to hide and show the content) I've created a web page showing step by step the two problems I'm encountering. This problem is much easier to see than it...
24
6341
by: firstcustomer | last post by:
Hi, Firstly, I know NOTHING about Javascript I'm afraid, so I'm hoping that someone will be able to point me to a ready-made solution to my problem! A friend of mine (honest!) is wanting to have on his site, a Javascript Calculator for working out the cost of what they want, for example: 1 widget and 2 widglets = £5.00
2
3844
by: Thomas T. Veldhouse | last post by:
Hello. I have been working with a client of mine on their seriazation code and we seem to have run into an issue when we migrated from .NET 1.1 to .NET 2.0. We have a framework of business objects that are serialized for persistant storage. The object graph DOES change as development continues, but it is required that we be able to deserialized existing classes and handle it properly (version tolerance). With version 1.1 of the .NET...
26
1781
by: optimistx | last post by:
A variable in global scope var a1 = 'contents of global variable a1'; can be references (with some limitations) as window; // or window.a1; // or even window;
0
10199
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
1
9979
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
8861
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
7393
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6661
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5293
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5433
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
3551
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2810
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.