Memory Arena Exception Security

I am writing a simple memory arena allocator and run into a small exception security issue. The situation is that you select an object that itself calls the allocator. The purpose of a memory pool is to allocate a bunch of objects at a time, and then delete them all when the pool is destroyed.

{ MemoryArena m; std::string* ptr = m.Allocate<std::string>(); // use ptr whatever // Cleaned up when pool is destroyed } 

But it becomes rather unpleasant when it is used several times. If the internal distribution is cleared, then it can be used subsequently - not a bad assumption, since the definition of the pool never removes objects until its life time has ended. consider the following issues:

 struct X { X(MemoryArena* ptr, std::string*& ref) { ref = ptr->Allocate<std::string>(); throw std::runtime_error("hai"); } }; MemoryArena m; std::string* ptr; m.Allocate<X>(&m, ptr); // ptr is invalid- even though it came from the arena // which hasn't yet been destroyed 

But if the internal allocation is not cleared, the external allocation also cannot be cleared, because the memory arena distributes them linearly, like on the hardware stack, so I am leaking memory. Therefore, either I violate my semantics by destroying an object earlier, or I lose my memory.

Any suggestions to fix this problem?

+1
c ++ c ++ 11
Dec 21 2018-11-12T00:
source share
2 answers

Perhaps this is just an example of the code this applies to, but I don't think the user should assume that ptr valid when the constructor of X throws. It can also be reset before ref is assigned.

So, I would say, clean the inner object if you can (that is, if the front of the arena is at the end of the inner object). OK, the selection from the arena becomes invalid, which is not normal, but it is a distribution that should never have left the real world.

Perhaps you could make this explicit, with the concept of soft distribution. He is not guaranteed to live forever, because as yet "soft", he can be released back into the arena. Then constructor X would do something like:

 SoftPtr<std::string> tmp(ptr->SoftAllocate<std::string>()); stuff_that_might_throw(); ref = tmp.release(); 

Executing the SoftPtr destructor without first calling release means that the object reference was not shown. It calls the MemoryArena function, which does something like:

  • destroy object
  • check if this is the last distribution from the arena.
    • if so, subtract the size from the current arena position indicator
    • if not, do nothing (memory leak)

Thus, any number of sections can be "canceled" if it is performed in the reverse order.

+2
Dec 21 '11 at 18:16
source share

By the very semantics of memory pools, and, as you stated about yourself in the question, you can free only the pool as a whole, and not individual objects. But you want to do just that.

The ability to equip the brk-like dispenser with functions to get and set the next distribution address. This gives you a low level mechanism that you can use to build what you want from it.

0
Dec 21 '11 at 18:34
source share



All Articles