gpt4 book ai didi

c++ - 内存领域的异常安全

转载 作者:行者123 更新时间:2023-11-30 04:30:39 26 4
gpt4 key购买 nike

我正在编写一个简单的内存区域分配器并面临一个异常安全的小问题。这种情况是当您分配一个本身调用分配器的对象时。内存池的目标是一次分配一堆对象,然后在池被销毁时将它们全部删除。

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

但是当它被多次使用时,这会变得相当讨厌。如果内部分配被清理,那么它可以在以后使用——这不是一个坏的假设,因为它是池的定义,在它的生命周期结束之前永远不会删除对象。考虑:

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

但是如果内部分配没有被清理,外部分配也不能被清理,因为内存空间像在硬件堆栈上一样线性分配它们,所以我泄漏了内存。因此,要么我通过提前销毁对象来违反我的语义,要么我泄漏内存。

对于如何解决这个问题有什么建议吗?

最佳答案

也许这只是适用于示例代码,但我认为用户不应该假设 X 的构造函数抛出时 ptr 是有效的。它也可以在分配 ref 之前抛出。

所以我会说,如果可以的话,清理内部对象(即,如果竞技场的前面当前位于内部对象的末端)。好吧,来自竞技场的分配变得无效,这不正常,但这是无论如何都不应该进入现实世界的分配。

也许您可以使用“软”分配的概念来明确这一点。它不能保证永远存在,因为虽然仍然“软”,但它可以被释放回竞技场。然后 X 的构造函数会做类似的事情:

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

在没有先调用release 的情况下执行SoftPtr 的析构函数意味着没有公开对该对象的引用。它调用 MemoryArena 的一个函数,该函数执行如下操作:

  • 销毁对象
  • 检查这是否是竞技场的最新分配
    • 如果是,则从竞技场的当前位置指针中减去大小
    • 如果不是,什么也不做(内存泄漏)

因此,只要以相反的顺序完成,任何数量的分配都可以“退出”。

关于c++ - 内存领域的异常安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8592018/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com