【问题标题】:Shared pointer to array in pool-allocated memory指向池分配内存中数组的共享指针
【发布时间】:2021-12-09 07:01:35
【问题描述】:

我正在编写一个容量固定、写入时复制的“字符串”类,该类能够使用分配器进行内存分配。最终,我希望能够让这些“字符串”使用返回固定大小的内存块的内存池。如果正在创建的字符串的“容量”小于池块大小,则额外的内存被“浪费”。如果容量更大,这是断言失败(即,您不能创建大于池块大小的字符串)。

为了实现写时复制行为,我试图弄清楚如何使用这个池在这块内存中创建指向数组的共享指针。我不能只使用 std::shared_ptr(pool.allocate(...)) 因为我需要在池分配的同一块内存中分配控制块和内存。

在视觉上,内存应该是这样的:

----------------------------------------------------
|              Memory Pool Chunk                   |
|--------------------------------------------------|
| Control Block | Array of characters ... | UNUSED |
----------------------------------------------------

根据我的研究,我可以看到这是 std::make_shared 所做的示例;它在一块连续的内存中分配控制块和对象。但是,您似乎也无法使用 std::make_shared 分配任意大小的数组。你可以使用它来分配 std::array 对象,但是你当然需要在编译时知道大小,而我要分配的数组的大小在运行时是已知的。

我的下一个想法是简单地实现我自己的,剥离共享指针。由于我不需要弱指针或自定义删除器,因此我似乎应该能够将分配器和引用计数存储在我从池中返回的内存中的某种“标题”中。然后,剩余的内存可以用于数组。

但是,我无法弄清楚您应该如何将分配存储在标头中,然后使用分配器来制作数据的深层副本。

有人可以帮忙吗:

a) 引导我使用已经内置的标准库结构或

b) 帮我弄清楚如何实现我自己的满足上述要求的共享指针

【问题讨论】:

  • 为什么要尝试分配(子分配)可变大小的块?如果您的字符串必须位于单个块中,则始终将整个块分配给 Control-block+string-data。所以你的字符串结构总是固定大小的。
  • @RichardCritten 除非我弄错了,否则这应该适用于所有分配器。因此,例如,如果我使用普通堆而不是池,则字符串大小没有限制。但是,如果我使用池,现在有一个限制。
  • 这正是std::allocate_shared 的用途。
  • 我觉得你的设计......令人困惑。池分配器的全部意义在于分配应该非常便宜。写时复制字符串的全部意义在于避免昂贵的分配。因此,您正在尝试使用一种旨在避免昂贵操作的技术,而该操作的版本非常便宜。这是一个很大的脱节。
  • @Frank 如果我错了,请纠正我,但看看标准,这似乎只适用于 C++20 中的数组。我最多只能使用 C++17。

标签: c++ c++17 shared-ptr allocator


【解决方案1】:

我会避免尝试为此使用shared_ptr。不仅因为您需要 C++20 才能使 allocate_shared 处理数组,还因为它对于您的嵌入式需求效率低下。

shared_ptr 控制块有两个引用计数以允许弱指针。您的特定用例不需要弱指针,因此您只需要一个计数。控制块有一个指向它管理的对象的指针。在您的用例中,数组始终位于控制块之后。控制块有一个分配器的副本,但是你的字符串类已经有了它,所以它在控制块中不需要它。以此类推。

您应该使用手动解决方案,这样您就可以最大限度地减少簿记内存量,从而最大限度地提高您获得的实际字符串存储量。

【讨论】:

    猜你喜欢
    • 2015-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 2018-10-09
    • 2015-06-19
    • 1970-01-01
    相关资源
    最近更新 更多