Re: a simple type-based C++ region allocator...
I forget to mention a major caveat. This is not the fault of region
allocation, but is related to C++ dtors. C-based regions do not have the
following problem: You should not access an object A which belongs to the
same allocator in the dtor of object B. Example of the problem, and a fix:
______________________________________________________________________
// snip region allocator code
#include <cstdio>
class foo {
foo* const m_other;
public:
foo() : m_other(NULL) {
std::printf("(%p)->foo::foo()\n", (void*)this, NULL);
}
foo(foo* const f) : m_other(f) {
std::printf("(%p)->foo::foo(%p)\n", (void*)this, (void*)f);
}
~foo() {
if (m_other) {
m_other->oops();
}
std::printf("(%p)->foo::~foo() - %p\n",
(void*)this, (void*)m_other);
}
void oops() {
std::printf("(%p)->foo::oops() - %p\n",
(void*)this, (void*)m_other);
}
};
int main() {
{
region_allocator<foo> foo_alloc;
foo* f1 = foo_alloc.allocate();
foo* f2 = foo_alloc.allocate(f1);
foo_alloc.flush();
std::puts("_________________________________________");
region_allocator<foo> foo_alloc_other;
f1 = foo_alloc_other.allocate();
f2 = foo_alloc.allocate(f1);
foo_alloc.flush();
foo_alloc_other.flush();
}
return 0;
}
______________________________________________________________________
Here is the output I get:
(003E4B98)->foo::foo()
(003E4B9C)->foo::foo(003E4B98)
(003E4B98)->foo::~foo() - 00000000
(003E4B98)->foo::oops() - 00000000
(003E4B9C)->foo::~foo() - 003E4B98
_________________________________________
(003E6BB8)->foo::foo()
(003E4B98)->foo::foo(003E6BB8)
(003E6BB8)->foo::oops() - 00000000
(003E4B98)->foo::~foo() - 003E6BB8
(003E6BB8)->foo::~foo() - 00000000
YIKES! Take note of the first section: Notice how foo(003E4B98) gets dtor'd
in line 3, but its member function `foo::oops()' get invoked from
foo(003E4B9C) in line 4? This is bad. It can cause undefined behavior, or it
can simply seg-fault if the region that foo(003E4B98) belonged to was
already freed.
Now take not of the second section: Notice how the member function
`foo::oops()' gets invoked on a valid object? This is because both objects
belong to different regions, and they get destroyed in the proper order.
I am very sorry for not mentioning the massive caveat earlier. Although, one
can most certainly make this exact same mistake with new/delete; example:
______________________________________________________________________
#include <cstdio>
class foo {
foo* const m_other;
public:
foo() : m_other(NULL) {
std::printf("(%p)->foo::foo()\n", (void*)this, NULL);
}
foo(foo* const f) : m_other(f) {
std::printf("(%p)->foo::foo(%p)\n", (void*)this, (void*)f);
}
~foo() {
if (m_other) {
m_other->oops();
}
std::printf("(%p)->foo::~foo() - %p\n",
(void*)this, (void*)m_other);
}
void oops() {
std::printf("(%p)->foo::oops() - %p\n",
(void*)this, (void*)m_other);
}
};
int main() {
{
foo* f1 = new foo();
foo* f2 = new foo(f1);
delete f1;
delete f2;
}
return 0;
}
______________________________________________________________________
output:
(003E4B10)->foo::foo()
(003E2BB0)->foo::foo(003E4B10)
(003E4B10)->foo::~foo() - 00000000
(003E4B10)->foo::oops() - 00000000
(003E2BB0)->foo::~foo() - 003E4B10
You have just got to be very careful!
:^o