自定义分配器可以替代智能指针的向量?

j00*_*0hi 14 c++ shared-ptr allocator unique-ptr c++11

这个问题是关于拥有指针,使用指针,智能指针,向量和分配器的。

我对代码体系结构的想法有些迷茫。此外,如果这个问题在某个地方已经有答案,1.抱歉,但是到目前为止我还没有找到满意的答案,并且2.请指出。

我的问题如下:

我有一个存储在向量中的“事物”,以及这些“事物”的几个“消费者”。因此,我的第一次尝试如下所示:

std::vector<thing> i_am_the_owner_of_things;
thing* get_thing_for_consumer() {
    // some thing-selection logic
    return &i_am_the_owner_of_things[5]; // 5 is just an example
}

...

// somewhere else in the code:
class consumer {
    consumer() {
       m_thing = get_thing_for_consumer();
    }

    thing* m_thing;
};
Run Code Online (Sandbox Code Playgroud)

在我的应用程序中,这是安全的,因为在任何情况下,“事物”的寿命都超过了“消费者”。但是,可以在运行时添加更多的“事物”,这可能会成为问题,因为如果std::vector<thing> i_am_the_owner_of_things;重新分配了这些事物,则所有thing* m_thing指针都将变为无效。

一种解决方案是将唯一的指针存储到“事物”,而不是直接存储“事物”,即如下所示:

std::vector<std::unique_ptr<thing>> i_am_the_owner_of_things;
thing* get_thing_for_consumer() {
    // some thing-selection logic
    return i_am_the_owner_of_things[5].get(); // 5 is just an example
}

...

// somewhere else in the code:
class consumer {
    consumer() {
       m_thing = get_thing_for_consumer();
    }

    thing* m_thing;
};
Run Code Online (Sandbox Code Playgroud)

这里的缺点是“事物”之间的内存一致性丢失了。可以通过使用自定义分配器重新建立此内存一致性吗?我在考虑类似分配器的事情,该分配器总是一次为例如10个元素分配内存,并且在需要时会添加更多10个元素大小的内存块。

示例:
最初:
v = ??????????
更多元素:
v = ?????????? ??????????
再次:
v = ?????????? ?????????? ??????????

使用这样的分配器,我什至不必使用std::unique_ptrs的“事物”,因为在std::vector重新分配时,已经存在的元素的内存地址不会改变。

作为替代方案,我只能考虑通过a来引用“消费者”中的“事物” std::shared_ptr<thing> m_thing,而不是当前的事物,thing* m_thing但这似乎对我来说是最糟糕的方法,因为“事物”不应拥有“消费者”并与他人共享指针,我将创建共享所有权。

那么,分配器方法是一种好方法吗?如果是这样,怎么办?我必须自己实现分配器,还是已有分配器?

lub*_*bgr 12

如果您能够将其thing视为值类型,请这样做。它简化了事情,您不需要智能指针即可规避指针/引用无效问题。后者可以用不同的方式处理:

  • If new thing instances are inserted via push_front and push_back during the program, use std::deque instead of std::vector. Then, no pointers or references to elements in this container are invalidated (iterators are invalidated, though - thanks to @odyss-jii for pointing that out). If you fear that you heavily rely on the performance benefit of the completely contiguous memory layout of std::vector: create a benchmark and profile.
  • If new thing instances are inserted in the middle of the container during the program, consider using std::list. No pointers/iterators/references are invalidated when inserting or removing container elements. Iteration over a std::list is much slower than a std::vector, but make sure this is an actual issue in your scenario before worrying too much about that.

  • @ j00hi两者都使用一种类型的布局块链接列表。缺点是,在大多数实现中,块大小确实很小且没有增长-通常可以通过宏定义在某种程度上减轻小尺寸的大小-但同样应归因于分析而不是推测。 (2认同)
  • Nitpick,但是不是这样,实际上迭代器在`std :: deque :: push_back`和`std :: deque :: push_front`上无效,而不是对实际元素的引用吗?值得一提的是,这样就不会有人在后面插入迭代器时期望它保持有效。 (2认同)