STL Container插入元素和内存透视

发布于 2024-12-11 07:11:20 字数 402 浏览 0 评论 0原文

这个问题是 问题 的扩展,我想了解如何将元素插入 STL容器

假设我有一个对象;,我想将其插入到任何STL容器中,我知道有一个分配器的概念来处理记忆。但我无法理解实际对象是如何复制到STL内存中的。因此,当我调用Container.insert时,我的对象存储在堆栈上,STL如何创建该对象的副本并将该对象存储到其内存中。

任何模拟相同内容的等效 C++ 代码都会有所帮助。

This question is extension of the question I want to understand how the elements are inserted into the STL Container.

Suppose I have A object;, which I want to insert into any of the STL Container, I understand that there is concept of allocators which handles the memory. But I fail to understand that how the actual object is copied into STL memory. So my object is stored on the stack when I call Container.insert how does STL create copy of this object and stored this objects into its memory.

Any equivalent C++ code would be helpful which simulates the same.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

泪痕残 2024-12-18 07:11:20

该方法并不复杂。基本上,容器将从分配器获取内存,然后执行复制构造(在该内存上使用placement-new)。更容易看到的容器是vector

void push_back( T const & value ) {
   ensure_enough_capacity();
   new (end_ptr++) T( value );
}

其中ensure_enough_capacity()确定向量是否必须增长并执行此操作,也就是说,如果,它将最终调用分配器>size()==capacity()push_back 被调用时。

下一个复杂级别是列表,其中每个节点都是单独分配的,并且库必须管理一些额外的信息。在这种情况下,代码将类似于:

void push_back( T const& value ) {
    node* n = allocator::allocate( sizeof(node) );
    new (n) node( value, x, y );
}

其中 xy 是初始化节点的 nextlast< 的适当指针/code> 指针(对于 last 通常是指向最后一个节点的指针,对于 next 则是指向哨兵节点的指针——超出末尾无效),以及假设这个特定的构造函数将复制构造,然后修复所有引用的指针。

有序关联容器在管理平衡树方面具有额外的复杂性,但方法是相同的:分配一个足够大的块来容纳值和额外信息,然后使用placement-new来构建节点。剩下的就是数据结构的细节了。

The approach is not that complicated. Basically the container will obtain memory from the allocator and then perform copy-construction (with placement-new over that memory). The easier container to see is vector:

void push_back( T const & value ) {
   ensure_enough_capacity();
   new (end_ptr++) T( value );
}

Where ensure_enough_capacity() determines whether the vector has to grow and does it, that is, it will end up calling the allocator if size()==capacity() when push_back is called.

The next level of complexity is a list, where each node is allocated on its own, and there is some extra information that the library has to manage. In that case the code would look similar to:

void push_back( T const& value ) {
    node* n = allocator::allocate( sizeof(node) );
    new (n) node( value, x, y );
}

Where x and y are the appropriate pointers to initialize the node's next and last pointers (usually would be a pointer to the last node for last and a pointer to a sentry node --invalid beyond the end-- for next), and assuming that this particular constructor will copy-construct the value and then fix all referred pointers.

Ordered associative containers have the extra level of complexity of managing the balanced tree, but the approach is the same: allocate a block big enough to hold the value and the extra information, and then use placement-new to build the node. The rest are details of the data structure.

来世叙缘 2024-12-18 07:11:20

使用适当的复制构造函数(或者可能是 C++11 中的移动构造函数)复制对象。假设您已预先分配了一个包含 N 个 Foo 对象的数组,并且其中已有 length 对象,则 std::vector 中的代码可能会看起来像:

void std::vector<Foo>::push_back( const Foo& n ) { 
    new( my_memory+length ) Foo(n);
    ++length;
}

new后面的括号表示“placement new”,即在预分配的存储上调用new。

The object is copied using the appropriate copy constructor (or, maybe, the move constructor in C++11). Assume that you have pre-allocated an array of N Foo objects and have length objects already in it, the code in std::vector might look like:

void std::vector<Foo>::push_back( const Foo& n ) { 
    new( my_memory+length ) Foo(n);
    ++length;
}

The brackets after the new indicate "placement new", that is, calling new on pre-allocated storage.

对你的占有欲 2024-12-18 07:11:20

大多数插入函数的原型都是

void insert(const A& a);

采用 cost& 本质上是一种传递值而不将其复制到形式参数的方法。

容器 - 取决于它们的工作方式 - 具有包含 A 的内部结构。
例如,一个列表有一个

struct node
{
   A val;
   node* next;
   node* prev;

   node(const A& a) :val(a), next(), perv()
   { }  
};

Insert,此时不只需要注意

void insert(const A& a)
{
   node* n = new(allocator.allocate()) node(a);
   /*set next and prev accordingly to list functionality*/
}

该引用通过节点构造函数传递并传递给节点嵌入的 A 的初始值设定项,即它自己的复制构造函数。

请注意,allocator.allocate() 实际上必须为节点分配空间,而不仅仅是 A。因此,列表中的分配器实例的类型将是 typename Allocator::rebind::other ,其中 Allocatorlist 的第二个模板参数,默认为 std::allocator

The most of the insert functions are prototyped as

void insert(const A& a);

Taking a cost& is -essentially- a way to pass a value without copy it in to the formal parameter.

Container -depending on how they work- have an internal structure that contains As.
For example, a list has a

struct node
{
   A val;
   node* next;
   node* prev;

   node(const A& a) :val(a), next(), perv()
   { }  
};

Insert, at that point does noting more than

void insert(const A& a)
{
   node* n = new(allocator.allocate()) node(a);
   /*set next and prev accordingly to list functionality*/
}

The reference is passed through the node constructor and given to the initializer for the node's embedded A, that's its own copy constructor.

Note that allocator.allocate() atually has to allocate space for node, not just A. For that reason the allocator instance inside the list will be of type typename Allocator::rebind<node>::other, where Allocator is the second template parameter of list, that defaults to std::allocator<A>.

掀纱窥君容 2024-12-18 07:11:20

内存分配方面真正发生的情况是:_it 使用作为 allocator 模板参数传入的分配器。

 map<int , long , less<int> , myAllocator<pair<int, long> > > myMap;

无论您做什么 myAllocator ,它的分配(如果有)都将被使用。从技术上讲,这意味着您可以预先分配所有对(可能来自向量)。它还意味着正在使用新的放置,就像在向量情况下一样,只是,对于小分配,您的分配将被多次调用,而不是单个连续分配。

这只会导致容器无法保证存储是连续的(就像向量情况一样),但是,由于实现的原因,它可能仍然是连续的 编写分配器

是一个高级主题,已在

what really happens in terms of memory allocation is this: _it uses the allocator passed in as the allocator template parameter.

 map<int , long , less<int> , myAllocator<pair<int, long> > > myMap;

whatever you make myAllocator do it's allocations from (if any) will be used. This technically means that you could preallocate all the pairs (perhaps from a vector). It also implicates that placement new is being used, just like in the vector case, only that, instead of a single contiguous allocation, your allocation will be called many times for small allocations.

This only leads to the situation where the container cannot guarantee that storage is contiguous (like in the vector case), however, it miht still happen to be contiguous due to the implementation of your allocator

Writing allocators is an advanced topic and it has been addressed in

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文