【发布时间】:2018-12-19 11:05:25
【问题描述】:
我目前对标准容器中的内存管理的理解有些困难,尤其是std::vector。
我很清楚std::vector 将在添加元素后调整大小,如果没有足够的保留空间,因此移动每个元素并更改内存中的地址。我现在的问题是:元素的成员变量会发生什么?
我的问题是基于我目前在std::vector 中管理我的游戏引擎的场景。场景由包含std::vector 的Scenes 的Scene 管理器类管理。添加场景如下所示:
std::vector<Scene> scenes;
Scene* active;
...
Scene scene;
scenes.emplace_back(scene);
active = &scenes.back();
场景是堆栈分配的,离开方法后将被丢弃。为了将当前添加的场景暴露给外部,我存储了一个指向 std::vector 后面的指针,这是新插入的元素。
Scenes 包含各种成员,例如Light 类的实例。由于各种原因,我还向外部公开了指向这些元素的指针。我的问题是我试图在Scene 的构造函数中使用这些指针,这些指针是在Scene 管理器中构造的。在将对象添加到std::vector 之后,即使似乎没有调用Scene 构造函数,似乎也构造了一个新对象。 “活动”成员现在包含与我之前分配的实际 Scene 对象不同的内存地址。由于矢量需要调整大小,我认为我很清楚。
但是场景中的成员会发生什么?原来的Scene 将被破坏,活动元素获得另一个内存地址。这意味着由于内部调整大小,它指向一个全新的元素,并且该新元素具有新成员,并且在我的情况下是我想要使用的那些。
我的理解是否正确?
我的第二个问题包括我应该如何处理这样的情况:我想公开指向存储在 std::vector 中的对象成员的指针,但大小未知。我目前选择的方法效果很好,但我不确定这是否是正确的方法:
在Scene 类中有一个onActivate 事件方法,它将在整个调整大小和获取向量的插入元素完成后调用。当我切换活动指针时,该方法也会被调用。该方法获取指向场景成员的指针并传递它们。它看起来像这样:
void postConstruct() {
std::cout << "postConstruct: " << &el << std::endl;
}
并将在 Scene 管理器中的正确位置调用,该管理器当前是 friend 到 Scene 类,因为这些事件不应暴露给外部世界。
active->postConstruct();
这是正确的方法吗?
【问题讨论】:
-
请记住,当
std::vector需要放大自身时,它可以重新分配已使用的内存。这意味着所有指向元素的迭代器和指针都变得无效并且不能再使用。因此,保存指向向量元素的指针并不是一个好主意。 -
指向向量元素的指针的值旨在在调整向量大小后始终刷新,这是从外部访问向量元素的唯一方法。我计划稍后用地图替换矢量,但现在我对这种访问方法很好。
-
我需要明确地跟踪一个元素。我不确定 stl 容器是否适合以后使用,但现在这是我的情况。
-
通过“保留地址”,您是在问向量元素是否保持相同的地址?或者它们的指针成员在被移动/复制后是否保持相同的值?
-
"...移动每个元素并将地址保存在内存中。"不,我已经看到一个元素的内存地址没有被保留。我相信现有向量元素的索引是通过向量扩展保留的。即 push_back (超出当前容量)创建一个新的连续分配,并添加一个新索引。但是涉及到很多实现细节。示例:在 ubuntu 上,使用 g++,扩展(由后推引起)使连续内存加倍。
标签: c++ c++11 pointers vector stdvector