【问题标题】:STL Containers allocation placement newSTL Containers 分配放置新
【发布时间】:2011-07-15 07:30:53
【问题描述】:

我找不到这个问题的确切答案,因此在这里发布。 当我想到向量时,它需要在连续的内存位置构建对象。这意味着向量保持分配的内存,并且必须对被推入其中的对象进行就地构造(=放置新)。这是一个有效的假设吗?另外,这是否意味着容器正在手动调用析构函数而不是调用删除?我在这里缺少任何其他假设吗?这是否意味着我可以假设如果我选择编写,即使是为对象编写的自定义 new 也可能不会被调用?

列表使用 new 和 delete 也是有意义的,因为我们不需要连续的内存保证。那么,这种行为是驱动分配器行为的原因吗?请帮忙。 谢谢

【问题讨论】:

    标签: c++ stl vector containers placement-new


    【解决方案1】:

    您非常接近完全正确。 vector(和所有其他标准容器)进行分配的方式是使用 std::allocator 类,它支持在特定位置构造和销毁对象。在内部,这使用放置 new 和显式析构函数调用来设置和销毁对象。

    我说“非常接近完全正确”的原因是,可以通过提供新的分配器作为模板参数代替默认值来自定义 STL 容器获取内存的方式。这意味着理论上应该可以让 STL 容器以不同的方式构造和销毁对象,尽管默认情况下它们将使用标准放置 new。

    【讨论】:

    • 第一段正确,第二段错误。容器必须使用作为模板参数提供的分配器,并在通过它们分配的内存上使用 placement new。 STL 容器不能以不同的方式构造和销毁,它们必须从分配器获取内存,并且必须通过使用void* 调用 placement new构造参数,因为这是构造一个不暗示内存分配的对象的唯一方法。
    • @David Rodriguez- 我认为容器内部使用分配器的构造和破坏成员函数,IIRC 不需要使用新的放置。如果不使用特定于编译器的功能,我看不出他们会怎么做,但理论上他们可以。如果我对此有误,请纠正我。
    • 当前标准,在第 362 页,第 §20.1.5 节 [lib.allocator.requirements] 有表 32,其中包含分配器要求。表格的最后两行是:a.construct(p,t), (not used), Effect: new ((void*)p) T(t)a。 destroy(p), (not used), Effect: ((T)p)->~T()*,其中中间一栏明确说明这两种方法not used .为什么他们需要在界面中逃脱我
    【解决方案2】:

    这意味着 vector 保持分配的内存,并且必须对被推入其中的对象进行就地构造(=placement new)。这是一个有效的假设吗?

    是的

    另外,这是否意味着容器是手动调用析构函数而不是调用delete?

    是的

    我在这里是否缺少任何其他假设?这是否意味着我可以假设如果我选择编写,即使是为对象编写的自定义 new 也可能不会被调用?

    是的。考虑到即使在链表中,容器也不会分配您的类型的实例,而是分配一个包含该类型子对象的模板结构。对于一个包含至少两个指针(两个链接)和您类型的子对象的复杂类型的链表。实际分配的类型是那个node,而不是你的类型。

    此外,列表使用 new 和 delete 也是有意义的,因为我们不需要连续的内存保证。

    可以,但不能new/delete您类型的对象。

    那么,这种行为是驱动分配器行为的原因吗?

    我不太明白这部分问题。分配器是在标准中定义了一组约束的类,包括接口(@98​​7654323@、deallocate...)和语义(== 的含义是分配给一个的内存可以通过释放另一个,类中的任何其他状态都是不相关的)。

    可以出于不同的原因创建分配器并将其传递给容器,包括效率(如果您只分配一种类型的对象,那么您可能能够实现比malloc更有效的小块分配器——或者不是,视情况而定)。

    关于新位置的附注

    我一直觉得有趣的是,placement new 是一个似乎有两个不同含义的术语。一方面是就地构造对象的唯一方法。但它似乎也有完全不同的含义:构造这个从自定义分配器获取内存的对象

    事实上placement new只有一个含义,与in-place构造无关。第一种只是第二种情况,分配器由 18.4.1.3 中定义的实现(编译器)提供,不能重载。重载分配器的特定版本除了返回参数 (void*) 之外什么都不做,以便 new-expression 可以将其传递给构造函数并在由 (not) 分配的内存上构造对象被调用的 placement new 版本。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-22
      相关资源
      最近更新 更多