C++ 标准容器如何为其节点(内部结构)分配内存?

C++ 标准容器如何为其节点(内部结构)分配内存?,c++,C++,例如,如果std::set和std::map具有类型为的分配器,我无法理解它们如何为节点分配内存 std::allocator<Key> std::分配器 及 std::分配器 分别。据我猜测,在std::set中应该有这样的代码,例如: std::pair<iterator, bool> insert(const value_type& value) { ... Node * node = new Node(); node->

例如,如果std::set和std::map具有类型为的分配器,我无法理解它们如何为节点分配内存

std::allocator<Key> 
std::分配器

std::分配器
分别。据我猜测,在std::set中应该有这样的代码,例如:

std::pair<iterator, bool> insert(const value_type& value)
{
    ...
    Node * node = new Node();
    node->value = value;
    ...
    return InsertNode(node);
 }
std::成对插入(常量值\u类型和值)
{
...
Node*Node=新节点();
节点->值=值;
...
返回InsertNode(node);
}

std::成对插入(常量值\u类型和值)
{
...
Node*Node=新节点();
节点->p_值=a1.分配(1);
*(节点->p_值)=值;
...
返回InsertNode(node);
}
其中节点是一些内部结构,例如红黑树节点


所以问题是这个节点的内存是如何分配的?

您提供的分配器将恢复到节点结构的类型,然后用于分配节点

<> >代码> STD::分配器< /C>(默认)将调用<代码>运算符new <代码>,然后执行特定于实现的操作(通常调用<代码> MalOC )。C++中的(< / P> < P>分配器)(由于某种原因)将被键入。也就是说,特定的分配器类实例分配特定类型的对象

但是,由于容器可能需要分配的实际类型可能不同于容器的值类型(容器逻辑上包含的类型),因此分配器(主要)需要能够转换为分配任何其他类型对象的备用分配器实例。这个过程称为“重新绑定”,它是通过调用
allocator.rebind
启动的,其中
U
是系统想要实际分配的类型

新的分配器实例是原始分配器的反弹形式,必须从与原始分配器相同的内存池中进行分配。因此,重新绑定被视为基于类型的更改,而不是真正不同的对象

标准库容器的实现不允许使用
new
delete
;必须通过分配器执行分配内存中的所有动态取消/分配和对象创建/销毁


std::set
插入一个项时,它会将您的分配器重新绑定到某个节点类型,该节点类型内部包含
T
本身或足够正确对齐的存储,以便在其中创建
T
。然后,它将使用分配器接口创建该节点类型,并初始化它包含的
T
std::map
有点复杂,但本质上它的节点类型必须存储一个
和一个

它们是如何“反弹”的?什么分配器方法用于此目的?@AlexeyStarinsky-See。大致上,容器使用NodeAllocator=typename allocator::template rebind重新绑定分配器,类似于
,它可以从原始分配器构造(根据所需的有效表达式
A(b)
)。所以他们可以转换它:
NodeAllocator-NodeAllocator(分配器)
请澄清一下,std::set是否允许客户端提供NodeAllocator实例,就像分配器允许将其实例作为构造函数参数传递一样?NodeAllocator可能是这样创建的NodeAllocator nodeAlloc(alloc);alloc是分配器实例。我不太明白你的问题是什么——你不清楚内存分配过程是什么?正如答案所解释的,
allocator::allocate
在某个点被调用,它调用
操作符new
,它执行
malloc
。您是否想知道在
allocate()
或其返回值之前会发生什么,或者您是在问
malloc()
是如何工作的?@Chronial我不是问std::allocator是如何实现的,而是问std::set是如何实现的。它如何使用分配器分配键和节点,而分配器::allocate()返回类型是Key*?
allocator.rebind
在C++17中被弃用,现在有了
std::allocator\u traits::template rebind\u alloc
@AlexeyStarinsky为什么不能使用
std::allocator\u traits::rebind\u alloc
模板
是必要的吗?@zjyhjqs:是的,
模板
是必要的。编译器需要知道依赖名称
rebind\u alloc
是否为模板。毕竟,编译器不知道它是否应该解释
@nicolasbolas,我仍然不明白
模板
为什么连接在
std::allocator\u traits
后面?我以前没见过这样的语法,你能给我一些参考资料,甚至一些关键字吗。谢谢。@Nicolas,我也不知道如何使用它。例如,对于类型
T
,我有一个树节点类型
TreeNode
,还有一个分配器
allocator
。我是否应该编写std::allocator\u traits::template rebind\u traits
std::pair<iterator, bool> insert(const value_type& value)
{
    ...
    Node * node = new Node();
    node->value = value;
    ...
    return InsertNode(node);
 }
std::pair<iterator, bool> insert(const value_type& value)
{
    ...
    Node * node = new Node();
    node->p_value = a1.allocate(1);
    *(node->p_value) = value;
    ...
    return InsertNode(node);
 }