可识别分配器的`std :: array`样式的容器?

时间:2019-08-14 02:47:44

标签: c++ c++17 allocator c++20 stdarray

我正在编写一些处理密码秘密的代码,并创建了ZeroedMemory的自定义std::pmr::memory_resource实现,该实现可以处理释放时的内存清理并使用必须使用的魔术来封装优化编译器,以消除操作。这样做的目的是避免专门化std::array,因为缺少虚拟析构函数意味着在类型擦除后进行破坏会导致释放内存而不进行清理。

不幸的是,我后来才意识到std::array不是AllocatorAwareContainer。我的std::pmr::polymorphic_allocator方法有点误导,因为std::array中显然没有空间存储指向特定分配器实例的指针。尽管如此,我仍然无法理解为什么不允许使用std::allocator_traits<A>::is_always_equal::value == true的分配器,而且我可以轻松地将解决方案重新实现为通用的Allocator而不是易于使用的{{1 }} ...

现在,我通常可以只使用std::pmr::memory_resource来代替,但是std::pmr::vector的一个不错的功能是数组的长度是类型的一部分。例如,如果要处理32字节的密钥,则不必进行运行时检查,以确保有人将传递给我的函数的std::array参数的长度正确。实际上,这些代码很好地转换为std::array<uint8_t, 32>,极大地简化了需要与C代码互操作的编写函数,因为它们使我基本上可以免费处理来自任何源的任意内存块。

具有讽刺意味的是,const std::span<uint8_t, 32>采用了分配器...但是我不禁想像要处理32字节std::tuple所需的typedef。

因此:是否有任何标准格式的类型可容纳固定数量的同类型项,即la std::tuple<uint8_t, uint8_t, uint8_t, uint8_t, ...>,但具有分配器感知能力(最好将这些项存储在相邻区域中,因此可以向下投射到std::array)?

2 个答案:

答案 0 :(得分:2)

这听起来像是XY问题。您似乎在滥用分配器。分配器用于处理运行时内存分配和释放,而不是挂钩堆栈内存。您要尝试执行的操作-使用后将内存清零-实际上应该使用析构函数来完成。您可能要为此编写一个类Key

class Key {
public:
    // ...
    ~Key()
    {
        secure_clear(*this); // for illustration
    }
    // ...
private:
    std::array<std::uint8_t, 32> key;
};

您可以轻松实现迭代器和跨度支持。而且您不需要使用分配器。

如果您想减少样板代码并使新的类自动迭代器/ span友好,请使用继承:

class Key :public std::array<std::uint8_t, 32> {
public:
    // ...
    ~Key()
    {
        secure_clear(*this); // for illustration
    }
    // ...
};

答案 1 :(得分:2)

您需要编译器和OS的配合才能使这种方案起作用。 P1315是解决事物的编译器/语言方面的建议。对于操作系统,您必须确保内存从未调出到磁盘等位置,以使内存真正为零。