C++ STL容器分配放置新

C++ STL容器分配放置新,c++,stl,vector,containers,placement-new,C++,Stl,Vector,Containers,Placement New,我找不到这个问题的确切答案,因此在这里发布。 当我想到vector时,它需要在一个连续的内存位置构建对象。这意味着vector保持内存分配,并且必须对推入其中的对象进行就地构造(=放置新对象)。这是一个有效的假设吗?另外,这是否意味着容器正在手动调用析构函数,而不是调用delete?我在这里遗漏了其他的假设吗?这是否意味着,如果我选择编写,即使是为对象编写的自定义新文件也可能不会被调用 列表使用new和delete也是有意义的,因为我们不需要连续的内存保证。那么,这种行为是驱动分配器行为的原因吗

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

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

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

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

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

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

我在这里遗漏了其他的假设吗?这是否意味着,如果我选择编写,即使是为对象编写的自定义新文件也可能不会被调用

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

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

确实如此,但它不会删除您类型的对象

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

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

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

关于新位置的旁注

我一直觉得有趣的是,“新位置”这个词似乎有两种不同的含义。一方面是在适当位置构造对象的唯一方法。但它似乎也有完全不同的含义:构造这个对象,从自定义分配器获取内存


事实上,新位置有一个单一的含义,它与就地构建无关。第一个只是第二个的一个例子,其中分配器由18.4.1.3中定义的实现(编译器)提供,不能重载。重载分配器的特定版本除了返回参数(
void*
)外,什么也不做,这样新表达式就可以将其传递到构造函数中,并在调用的新版本所分配的内存(not)上构造对象。

第一段是正确的,第二段不是。容器必须使用作为模板参数提供的分配器,并在通过它们分配的内存上使用placement new。STL容器不能以不同的方式构造和销毁,它们必须从分配器获取内存,并且必须通过使用
void*
参数调用placement new来构造,因为这是构造一个不意味着内存分配的对象的唯一方法。@David Rodriguez-我认为容器内部使用分配器的构造和析构函数,IIRC不需要使用这些函数。我不知道如果不使用特定于编译器的特性,他们还能做什么,但理论上他们可以做到。如果我在这方面有错误,请纠正我。当前标准第362页§20.1.5节[库分配器要求]中有表32,其中包含分配器要求。表的最后两行是:a.construct(p,t),(未使用)、Effect:new((void*)p)t(t)和a.destroy(p),(未使用)、Effect:((t)p)->~t()*,中间一列清楚地表明这两种方法未使用。我不明白为什么在接口中需要它们