C++ 如何根据STL列表中的元素数量分配内存?

C++ 如何根据STL列表中的元素数量分配内存?,c++,stl,allocator,C++,Stl,Allocator,有一个选项可以为STL容器提供自定义分配器。但是,我找不到一个在内存池耗尽空间后可以增加内存池块大小的实现。STL分配器如何读取列表容器的大小并自增长块大小 例如,块大小从1、2、4等开始,然后当容器中有1、3、7个节点时,块大小在下一次插入后立即增大。标准容器使用提供的分配器(调用其成员函数)分配它们所需的内存。相反的情况不会发生——按照标准的规定,分配器接口中没有任何内容允许它获得关于使用它的容器的信息。这意味着,只要自定义分配器具有标准中要求的相同接口,就没有查询容器大小的方法 要执行您想

有一个选项可以为STL容器提供自定义分配器。但是,我找不到一个在内存池耗尽空间后可以增加内存池块大小的实现。STL分配器如何读取列表容器的大小并自增长块大小


例如,块大小从1、2、4等开始,然后当容器中有1、3、7个节点时,块大小在下一次插入后立即增大。

标准容器使用提供的分配器(调用其成员函数)分配它们所需的内存。相反的情况不会发生——按照标准的规定,分配器接口中没有任何内容允许它获得关于使用它的容器的信息。这意味着,只要自定义分配器具有标准中要求的相同接口,就没有查询容器大小的方法

要执行您想要的操作,您需要一个具有不同于标准分配器接口的专用分配器,以及一个知道如何与该专用分配器通信的自定义容器(例如,替换
std::list
)。试图让您的自定义分配器与标准容器一起工作,或者让您的自定义容器与标准分配器一起工作,将无法正常工作—接口将不兼容

此外,您描述的行为(每次分配加倍)特定于标准库的实现。虽然这种分配策略有些常见,但标准并不要求它。其他实现是允许的——有些确实允许——使用不同的分配策略


最后,计算/估计容器大小的上限可能会更容易,使用该上限计算出程序需要运行的内存量,并至少安装该内存量。

分配器通常不依赖于作为其客户端的容器类型,这将是一种循环依赖关系。这个循环需要通过某种不完整的类接口或类型擦除来解决

例如,对于不完整的类指针:

struct my_pool;

template< typename t >
struct my_allocator {
    my_pool * pool;
    // allocate, deallocate, etc.
};

struct my_pool {
    std::list< foo, my_allocator< foo > > const * client;
};

std::list< foo, my_allocator< foo > > things;
my_pool.client = & things;
这个池甚至不需要知道容器类型


但是,无论哪种情况,这似乎都不是特别好的设计。池不能被其他容器共享,至少不能平等共享。

您能更清楚地说明这一需要的目的吗?我知道您想从分配器那里知道在列表中您分配了多少元素。您可以通过简单地计算从分配器中释放的分配数量来实现这一点。但是,这对您有什么帮助?不确定此链接是否可以帮助您,如果您将节点从一个列表拼接到另一个列表,会发生什么情况?@MSalters它们将共享相同的内存池,因此如果两个列表都不共享(或不共享),则两个列表都应取消分配操作。问题是,决定分配策略(从分配器请求多少内存)的是容器,而不是分配器。如果分配器分配的内存少于容器请求的内存,那么当容器试图使用它请求的内存时,它将表现出未定义的行为,但分配器没有提供这些内存。@Peter问题不清楚,但在我看来,分配器根据特定容器的大小决定如何扩展池。在任何情况下,只要分配器的
allocate
方法按要求工作,一切都正常。是的,OP错误地认为是分配器决定了分配策略。但是,如果分配器
allocate()
返回的大小与请求的大小不同(特别是更小),则容器不会收到指示该大小的信息。换句话说,
allocate()
必须至少返回请求的金额,否则将失败(例如,标准分配器抛出)。@Peter我们可能都对这个问题有过深入的了解。我们读的不一样,也许吧。我的看法是,OP希望能够向标准容器提供一个分配器,该容器可以更改用于分配内存的策略。这是不可能的,因为容器决定分配策略,而不是分配器。分配器只服务于内存请求(来自它所管理的任何内存源)。容器发出这些请求。分配策略是容器决定发出什么请求的手段。
struct my_pool {
    std::function< std::size_t() > client_size;
};

std::list< foo, my_allocator< foo > > things;
my_pool.client_size = [&]{ return things.size(); };