如何判断 std::vector 是否调整了自身的大小,以及如何说明指向向量内的值的指针不再有效?

How to tell if std::vector resized itself, and how to account for pointers to values inside the vector no longer being valid?

我明白,如果 std::vector 被调整大小(我相信只是大小增加了),向量的内存位置将被重新定位,以便在堆内存中找到一个新的位置,这实际上将适合新尺寸。在那种情况下,如果我的指针 A、B 和 C 之前指向向量中的元素,它们将指向旧的、已取消分配的内存位置,并且不再有效。

我想知道 A:是否可以在发生此类事件时收到通知,而无需我明确管理何时调整 std::vector 大小,以及 B:如何处理指针 否不再引用内存中的正确位置。

B 部分有点含糊,所以我将缩小我想要使用此行为的用例范围。在我的情况下,我有一个 class 维护一个对象向量,这些对象内部有多个指针,如下所示:

class MultiPointer{
public:
    Type1* t1;
    Type2* t2;
    Type3* t3;
    MultiPointer(Type1*t1, Type2*t2, Type3*t3);
};
...
// attempt to create singleton pattern to make pool of each object type for each class
class Type1{
...
    static vector<Type1> arr1 = ...
}
class Type2{
...
    static vector<Type2> arr2 = ...
}
class Type3{
...
    static vector<Type3> arr3 = ...
}
...

//note, would actually use CRTP to make sure I don't have to type out static vector<TypeN> each time

MultiPointer a(&arr1[0], arr2[0], arr3[0]);
MultiPointer b(&arr1[1], arr2[1], arr3[1]);
MultiPointer c(&arr1[2], arr2[2], arr3[2]);
std::vector<MultiPointer> mpv= {a,b,c};
... insertions into arr1,2,3 ...
//How do I make sure that a, b, and c still point to the same types? 

请注意,在我的情况下,我可以随时访问 arr1->3 相关的内容,因为它是一个静态变量,而且我知道我正在使用的类型。

我的想法是将 arr1 的指针值复制到一个单独的变量中,即

Type1* arr1ptrcpy = &(Type1::arr1[0]);

然后我会在需要的时候检查大小是否改变了,如果大小改变了我会检查指针是否相同(或者只检查指针是否相同)

//ie in main
if(arr1ptrcpy != &(Type1::arr1[0])){
// for each multi pointer in mpv, adjust pointers for arr1. 
...
}

如果我注意到地址发生变化,我会进行指针算术运算以找到旧指针相对于新地址的正确位置。

// in MultiPointer
...
// if pointers don't match for arr1
t1 = (arr1ptrcpy - t1) + Type1::arr1[0];
...
// if pointers don't match for arr2
t2 = (arr2ptrcpy - t2) + Type2::arr2[0];
...
// if pointers don't match for arr3
t2 = (arr3ptrcpy - t3) + Type3::arr3[0];

虽然我可以使用句柄来完成这一切,但这需要运行时开销来取消引用指针,我会有很多指针。在这种情况下,与取消引用指针相比,我检查向量更改的频率要低得多。如果这可以用迭代器完成,每个迭代器没有额外的内存开销,我也愿意看看如何完成。

编辑:我想提供更多关于我的实际应用程序试图完成什么/它是如何构建的信息。在实际用例中,有多种类型的 MultiPointer,其中一些引用相同的对象,但指针类型不同(因此首先需要指针)并且它们引用的对象在上下文之外的其他地方使用多指针也是如此。

在我的实际应用程序中,'MultiPointer' 充当一组对象,这些对象具有附加到这些分组的不同功能。例如,您可能有一个具有 Position* 和 Velocity* 的 PhysicsMultiPointer,以及一个具有 DisplayImage* 和 Position* 的 GraphicMultiPointer。它们都将指向同一个 Position 对象。

第二次编辑:

我应该提一下,我需要类型向量中的所有元素都在连续的内存中,如果不是这种情况,我什至不会为这整个考验而烦恼,因为我只会有指向堆对象的指针,而堆对象不会'改变位置。

要在向量中的内部指针更改时得到通知,可以换行std::vector。您需要挂钩函数 push_back()emplace_back()resize()shrink_to_fit()(只需禁用那个)、reserve()insert() .只需检查之前和之后的 data() 就足够了,如果它发生变化则调用回调。

A: If it was possible to be notified when such an event happens, with out me explicitly managing when a std::vector is resized,

没有

您可以很容易地判断它何时会发生,但您无法在事后判断它何时发生。 vector 重新分配仅在您执行某些操作使 vector 的大小超过其当前 capacity(或者您调用 shrink_to_fit)时才会发生。因此,如果您将 4 个项目插入 vector,如果容量大小为 4 或更大,它不会重新分配自身。

现在,您可以使用这个事实为插入函数构建包装器functions/objects,它将检查插入前后的容量以及return是否发生了变化(如果发生重新分配,必须增加容量)。

然而,处理这个问题的更好方法是简单地……不要让它发生。使用 reserve 函数使容量足够大,您根本不需要重新分配。通过这样做,您将不必关心重置指针等问题。

请注意,以上仅涵盖由于重新分配而导致的指针失效。如果将对象插入 vector 的中间,指针和引用将失效,但只有那些 pointers/references 指向插入点处的元素和所有后续元素。

B: how to deal with the pointers no longer referencing the correct location in memory.

不要使用指针。相反,使用索引。除非你插入 vector 的中间;指数对此无能为力。

如果索引对您不起作用,那么我会强烈重新考虑使用 vector。如果您非常需要元素的稳定性,那么 listforward_list 似乎是更适合这项工作的工具。或者,如果您有权访问 Boost,boost::stable_vector.