|
Boost : |
From: Mathias Gaunard (mathias.gaunard_at_[hidden])
Date: 2008-04-23 20:29:00
shiwei xu wrote:
> This article consists of three parts:
>
> 1. What is GC Allocator?
> 2. GC Allocator implementations: ScopeAlloc and AutoFreeAlloc
> 3. Applications based on GC Allocator
> For more information, see
> http://www.codeproject.com/KB/cpp/gc-allocator.aspx
I only went through your article now.
First, this is not Garbage Collection at all. As a matter of fact, it
does not collect garbage at any time.
Second, this is no innovation. This is a single-threaded stack allocator
with private instances. Basically the fastest thing ever, indeed.
Having multiple instances or regions by itself has many advantages, such
as faster freeing, since you just have to free the whole regions without
walking the tree of objects, for example.
Stack allocation is simply the simplest algorithm and is extremely fast, yet
- you waste lots of memory
- you can't really give the memory back to the OS
- you can only free in the reverse order you allocated in. For example,
shared ownership is out of the question.
Single-threaded allocators are cool as long as you use a private heap
(or region) per thread, which of course has some cost in memory usage,
especially with stacks, and that you will be able to free what you
allocated with the same allocator you used to allocate it, that is to
say in the same thread.
That certainly does not fulfill any of the aims of the allocators and
smart pointers you've been comparing it too, since your "innovation" has
so many usage restrictions.
For example, you compared it to smart pointers such as auto_ptr and
shared_ptr (which are totally different and have different goals).
auto_ptr being deprecated in C++0x in favor of unique_ptr, I will thus
consider this one.
An unique_ptr actually owns the pointed-to value. A shared_ptr co-owns
the pointed-to value. That allows for example to put smart pointers into
standard containers. When the smart pointer is removed from the
container, it's also destructed and freed.
You cannot do that with your solution (and it couldn't work with a stack
anyway, containers don't expect LIFO usage restriction)
The only thing your allocators can really do is dynamically allocating
scope bound objects, just like when you declare variables on the stack.
That certainly is a good thing and can solve most problems.
Except your solution exposes pointers while it is not needed at all, and
thus is fairly unsafe and inelegant. You should make your allocators not
copyable, by the way.
Also in theory it is suboptimal, since you could simply allocate on the
execution stack; C++ however does not allow having objects of dynamic
size, which could potentially be problematic because of the
compile-time/run-time differentiation.
Actually, in all of your examples, there is no valid reason why one
should use dynamic memory allocation at all. Just declare those
variables on the execution stack.
Stack allocation also has an obvious issue: moving becomes as expensive
as copying.
Same for swapping, you need to move three times.
Also, you claimed this
{
std::auto_ptr<MyObj> obj(new MyObj);
std::auto_ptr<AnotherObj> obj2(new AnotherObj);
... // use obj and obj2 to do something.
}
was somewhat equivalent to this,
MyObj* obj = new MyObj;
AnotherObj* obj2 = new AnotherObj;
try
{
... // use obj and obj2 to do something.
}
catch (...)
{
delete obj;
delete obj2;
throw;
}
delete obj;
delete obj2;
Which is incorrect.
A possible equivalence would be:
{
MyObj* obj = new MyObj;
try
{
AnotherObj* obj2 = new AnotherObj;
}
catch(...}
{
delete obj;
throw;
}
try
{
... // use obj and obj2 to do something.
}
catch(...)
{
delete obj2;
delete obj;
throw;
}
delete obj2;
delete obj;
}
This certainly demonstrates that scope-bound resource management (aka
RAII) certainly reduces the annoyance in writing exception-safe code.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk