5

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

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

4

2 回答 2

4

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

是的

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

是的

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

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

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

它确实如此,但它不会new/delete您类型的对象。

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

我真的不明白这部分问题。分配器是具有标准中定义的一组约束的类,包括接口(allocatedeallocate...)和语义(含义==是分配给一个的内存可以与另一个释放,类中的任何其他状态无关紧要)。

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

关于安置新的旁注

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

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

于 2011-03-14T21:26:11.030 回答
3

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

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

于 2011-03-14T20:30:07.670 回答