为什么许多Allocator函数是可选的

Why are many Allocator functions optional?

本文关键字:函数 许多 Allocator 为什么      更新时间:2023-10-16

我刚刚完成了一个关于重写operator new和delete的个人项目,并在此过程中学习了有关分配器类的知识。在阅读了包括cppreference.com在内的一些在线参考资料后,我注意到许多函数被描述为可选的。

我的问题是,如果接收到的分配器只能选择性地实现函数和类型,那么分配器接收者(例如std::set)如何工作?

如果要求分配器从某些基类派生,这些基类对所有函数都有默认实现,我可以理解,但似乎对分配器没有继承要求。

还是因为编译错误而提醒人们需要实现这些可选函数?

作为参考,这是我第一次尝试使用分配器,我将它用作std::set的第三个模板参数。我完成了一个现有的示例,因此我相信我实现的大部分内容可能是不必要的,但我还不明白如果将来选择将分配器与其他STL容器一起使用,如何判断是否必要。除非,再一次,期望是根据编译错误来找出它…?

template <typename T>
class Allocator // Custom allocator for use by AllocSet::mAllocatedPtrs to avoid infinite recursion
{               // (because inserting an element in std::set calls ::operator new, which is overridden to add to AllocSet::mAllocatedPtrs).
    public:
        typedef T value_type;
        typedef T* pointer;
        typedef T& reference;
        typedef const T* const_pointer;
        typedef const T& const_reference;
        typedef size_t size_type;
        typedef ptrdiff_t difference_type;
        template <typename U>
        struct rebind { typedef Allocator<U> other; };
        Allocator() { }
        template <typename U> Allocator(const Allocator<U>&) { }
        virtual ~Allocator() { }
        pointer allocate(size_t numT) { return (T*)(malloc(numT * sizeof(T))); }
        void deallocate(pointer p, size_type st) { free(p); }
        size_type max_size() { return size_type(-1); }
        reference operator=(const_reference) { return *this; }
        template <typename U> reference operator=(const Allocator<U>&) { return *this; }
        template <typename U> bool operator==(const Allocator<U>&) { return true; }
        template <typename U> bool operator!=(const Allocator<U>&) { return false; }
        pointer address(reference r) { return &r; }
        const_pointer address(const_reference r) { return &r; }
};

我的问题是,如果接收到的分配器只能选择性地实现函数和类型,那么分配器接收者(例如std::set)如何工作?

如果你看看分配器的概念:

有些需求是可选的:模板std::allocator_traits提供了所有可选需求的默认实现,所有标准库容器和其他分配器感知类都通过std::allocator_traits访问分配器,而不是直接访问。

这也是为什么这么多东西是可选的原因——大多数分配器的实现实际上不需要改变它们,所以为什么要这么麻烦呢?假设你有一个新的内存重组算法的想法,为什么你需要定义pointer ?


还是因为编译错误而提醒人们需要实现这些可选函数?

不,分配器的概念定义得很好。它指定您必须提供什么,以及您可以提供什么。没有必要依赖于编译错误。

您可以在标准$17.6.3.5中找到这些要求。