我无法找到这个问题的确切答案,因此在此处发布。 当我想到vector时,它需要在连续的内存位置构建对象。这意味着向量保持内存分配,并且必须对被推入其中的对象进行就地构造(= placement new)。这是一个有效的假设吗?此外,这是否意味着容器手动调用析构函数而不是调用delete?我在这里缺少任何其他假设吗?这是否意味着我可以假设如果我选择写的话,即使是为对象编写的新自定义也可能不被调用?
同样有意义的是列表使用new和delete,因为我们不需要连续的内存保证。那么,这种行为是什么推动了分配器的行为?请帮忙。 感谢
答案 0 :(得分:4)
这意味着向量保持内存分配,并且必须对被推入其中的对象进行就地构造(= placement new)。这是一个有效的假设吗?
是
另外,这是否意味着容器是手动调用析构函数而不是调用delete?
是
我在这里缺少任何其他假设吗?这是否意味着我可以假设如果我选择写的话,即使是为对象编写的新自定义也可能不被调用?
是。考虑即使在链表中,容器也不会分配您的类型的实例,而是包含该类型的子对象的模板化结构。对于链接列表,它将是包含至少两个指针(两个链接)和您的类型的子对象的复杂类型。分配的实际类型是节点,而不是您的类型。
同样有意义的是列表使用new和delete,因为我们不需要连续的内存保证。
确实如此,但它不是您类型的new
/ delete
个对象。
那么,这种行为是驱动分配器行为的原因吗?
我真的不明白这部分问题。分配器是具有标准中定义的一组约束的类,包括接口(allocate
,deallocate
...)和语义(==
的含义是分配的内存如果一个可以与另一个解除分配,则该类中的任何其他状态都是无关紧要的)。
可以创建分配器并将其传递到容器上,原因各不相同,包括效率(如果您只分配一种类型的对象,那么您可能能够实现比malloc
稍微更高效的小块分配器 - 或者不,取决于具体情况)。
有关新展示位置的附注
我总是觉得有趣的是贴装新这个术语似乎有两个不同的含义。一方面是构建对象就地的唯一方法。但它似乎也有完全不同的含义:构造此对象从自定义分配器获取内存。
实际上 placement new 的含义与构建就地无关。第一种情况只是第二种情况,其中分配器由18.4.1.3中定义的实现(编译器)提供,不能重载。重载分配器的特定版本绝对不会返回参数(void*
),以便 new-expression 可以将它传递给构造函数并在内存上构造对象(不是)由被调用的 placement new 版本分配。
答案 1 :(得分:3)
你非常接近完全正确。 vector
(和所有其他标准容器)进行分配的方式是使用std::allocator
类,它支持在特定位置构造和销毁对象。在内部,它使用放置新的和显式的析构函数调用来设置和销毁对象。
我说“非常接近完全正确”的原因是,通过提供新的分配器作为模板参数来代替默认值,可以自定义STL容器如何获取内存。这意味着理论上应该可以让STL容器以不同的方式构造和销毁对象,但默认情况下它们将使用标准的新布局。