
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.