如何将状态传递给 STL 中的 rebind_alloc 构造函数?

How can I pass a state to the rebind_alloc constructor in STL?

假设我有一个要用于 STL 容器的自定义有状态分配器。容器将使用 rebind_alloc 特性来分配其内部元素,因此默认情况下(或通过定义 rebind<T>::other),我可以要求它使用我的分配器 class 作为内部元素嗯。

但是,我想传递我的分配器的状态。

此相关question问为什么

  template<class U> allocator( const allocator<U> & o ) throw()

存在并且答案表明我想做的是可能的。

但是,根据我的实验(基本上是在自定义分配器中跟踪对 Allocator()template <class U> Allocator(const Allocator<U> &other) 的调用),我无法调用 rebind_alloc 转换构造函数而不是默认构造函数。

其实很简单,如果容器的构造函数被赋予一个分配器实例作为参数,转换构造函数就会被调用。容器的构造函数必须知道分配器实例是合乎逻辑的。

例如,如果没有给容器任何参数,将使用分配器的默认构造函数。

#include <memory>
#include <set>
#include <iostream>
#include <type_traits>

void *default_allocator;

template <typename T>
struct Allocator
{
    using value_type = T;
    using pointer = T *;
    using size_type = size_t;

    int state;

    Allocator(int s) : state(s)
    {
        std::cout << "default with arg " << typeid(T).name() << std::endl;
        std::cout << "state " << state << std::endl;
    }

    Allocator() : Allocator(*static_cast<Allocator *>(default_allocator)) // state(static_cast<Allocator *>(default_allocator)->state)
    {
        std::cout << "default without arg " << typeid(T).name() << std::endl;
        std::cout << "state " << state << std::endl;
    }

    template <class U>
    Allocator(const Allocator<U> &other)
    {
        state = other.state;
        std::cout
            << "conversion " << typeid(T).name() << " from " << typeid(U).name() << std::endl;
        std::cout << "state " << state << std::endl;
    }

    pointer allocate(size_type n)
    {
        std::allocator<T> a;
        return a.allocate(n);
    }

    void deallocate(pointer p, size_type n)
    {
        std::allocator<T> a;
        a.deallocate(p, n);
    }
};

template <class T, class Compare = std::less<T>>
using set = std::set<T, Compare, Allocator<T>>;

int main()
{
    std::cout << "new Allocator<int>(10)" << std::endl;
    default_allocator = static_cast<void *>(new Allocator<int>(10));

    std::cout << std::endl;

    std::cout << "alloc(20)" << std::endl;
    Allocator<int> alloc(20);

    std::cout << std::endl;

    std::cout << "set<int> s1;" << std::endl;
    set<int> s1;

    std::cout << std::endl;

    std::cout << "set<int> s2(alloc);" << std::endl;
    set<int> s2(alloc);
}
new Allocator<int>(10)
default with arg i
state 10

alloc(20)
default with arg i
state 20

set<int> s1;
default without arg NSt3__111__tree_nodeIiPvEE
state 10

set<int> s2(alloc);
conversion NSt3__111__tree_nodeIiPvEE from i
state 20