内存领域的异常安全 [英] Exception safety in memory arena

查看:95
本文介绍了内存领域的异常安全的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个简单的内存竞技场分配器,并面临着异常安全的小问题.情况是当您分配一个本身称为分配器的对象时.内存池的目的是一次分配一堆对象,然后在销毁该池时将其全部删除.

I'm writing a simple memory arena allocator and facing a small problem with exception safety. The situation is when you allocate an object which itself calls the allocator. The objective of the memory pool is to allocate a bunch of objects at one 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 this gets rather nasty when it's used multiple times. If the inner allocation is cleaned up, then it could be used afterwards- not a bad assumption, since it's the definition of the pool to never delete objects until it's lifetime is over. consider:

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 inner allocation isn't cleaned up, the outer allocation also can't be cleaned up, because the memory arena allocates them linearly like on a hardware stack, so I leak memory. So either I violate my semantics by destroying an object early, or I leak memory.

关于如何解决此问题的任何建议?

Any suggestions for how to resolve this problem?

推荐答案

也许这只是适用于此的示例代码,但我认为用户不应该在ptr是有效的>抛出.在分配ref之前也可能抛出该错误.

Maybe it's just the example code that this applies to, but I don't think the user should assume that ptr is valid when the constructor of X throws. It could just as well have thrown before ref was assigned.

因此,我想说,如果可以的话,请清理内部对象(即,如果竞技场的前部当前位于内部对象的末端).好的,从竞技场分配的资源将变得无效,这是不正常的,但这是一个绝对不应该将其分配到现实世界中的分配.

So I'd say clean up the inner object if you can (i.e. if the front of the arena currently lies at the end of the inner object). OK, an allocation from the arena becomes invalid, which isn't normal, but it's an allocation that should never had made it out into the real world anyway.

也许您可以使用软"分配的概念来使之明确.它不能保证永远存在,因为尽管它仍然是软"的,但可以释放回竞技场.然后X的构造函数将执行以下操作:

Perhaps you could make this explicit, with a concept of a "soft" allocation. It's not guaranteed to live forever, because while still "soft" it can be freed back to the arena. Then X's constructor would do something like:

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

在没有先调用release的情况下执行SoftPtr的析构函数意味着没有公开对该对象的引用.它调用MemoryArena函数,其功能类似于:

Executing the destructor of SoftPtr without without first calling release implies that no reference to the object has been exposed. It calls a function of MemoryArena that does something like:

  • 破坏对象
  • 检查这是否是来自竞技场的最新分配
    • 如果是这样,请从竞技场的当前位置指针中减去大小
    • destruct the object
    • check whether this is the most recent allocation from the arena
      • if so, subtract the size from the arena's current position pointer
      • 如果没有,则什么也不做(内存已泄漏)

      因此,只要逆序完成,就可以撤回"任意数量的分配.

      So any number of allocs can be "backed out", provided it's done in reverse order.

      这篇关于内存领域的异常安全的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆