C++ C++;和标准容器:成员的内存地址

C++ C++;和标准容器:成员的内存地址,c++,c++11,pointers,vector,stdvector,C++,C++11,Pointers,Vector,Stdvector,我目前在理解标准容器中的内存管理方面遇到了一些问题,尤其是std::vector 我很清楚,std::vector在添加元素后,如果没有足够的空间保留,将调整大小,因此移动每个元素并更改内存中的地址。我现在的问题是:元素的成员变量会发生什么变化 我的问题是基于这样的想法:对于我的游戏引擎,我目前正在管理std::vector中的场景。场景由一个Scenemanager类管理,该类包含Scenes的std::vector。添加场景如下所示: std::vector<Scene>

我目前在理解标准容器中的内存管理方面遇到了一些问题,尤其是
std::vector

我很清楚,
std::vector
在添加元素后,如果没有足够的空间保留,将调整大小,因此移动每个元素并更改内存中的地址。我现在的问题是:元素的成员变量会发生什么变化

我的问题是基于这样的想法:对于我的游戏引擎,我目前正在管理
std::vector
中的场景。场景由一个
Scene
manager类管理,该类包含
Scene
s的
std::vector
。添加场景如下所示:

    std::vector<Scene> scenes;
    Scene* active;
...
        Scene scene;
        scenes.emplace_back(scene);
        active = &scenes.back();
并将在
场景
管理器的正确位置调用,该管理器目前是
场景
类的
朋友
,因为这些事件不应暴露于外部世界

    active->postConstruct();

这是正确的方法吗?

如果调整了
std::vector
的大小,则如果移动构造函数声明为
noexcept
,则将使用元素的移动构造函数移动元素,或者使用元素的复制构造函数将其复制到新分配的位置

重新分配后成员指针是否相同将取决于如何为插入的元素实现移动构造函数或复制构造函数


我建议使用index than
Scene*
来访问
std::vector
中的元素,或者使用
std::list
如果您想使用
Scene*

当展开
vector
时,所有迭代器、指针和对元素的引用都将无效。使用无效指针或迭代器可以执行的定义的唯一操作是用另一个值覆盖它,而使用无效引用不能执行任何操作。即使将该值与其他值进行比较,也会导致程序格式错误

当你这样做的时候

Scene scene; 
scenes.emplace_back(scene); 
active = &scenes.back();
您有两个
场景
对象。一个是局部变量,另一个在向量中,是从
场景
复制的。我不确定您是否意识到这种区别,您可能只需要一个
场景
对象。所有
场景
都存在于
场景
,或者您将其更改为
std::vector
,或者
std::vector
。如果执行后一种操作,请确保在销毁值之前将其删除

语言提供的复制构造函数将简单地复制每个成员的值,在指针的情况下,这往往是错误的。您可以为
场景
明确定义复制构造函数,以精确控制发生的情况,例如“深度复制”指针成员

class Copyable
{
    int* ptr;
public: 
    Copyable() : ptr(new int) {}
    ~Copyable() { delete ptr; }
    Copyable(const Copyable & other) : ptr(new int(*other.ptr)) {} // deep copy
    Copyable& operator=(const Copyable & other)
    {
        *ptr = *other.ptr;
        return *this;
    }
};
或者,您可以通过将复制构造函数定义为
=delete
d来禁止复制
场景
s

class UnCopyable
{
    int* ptr;
public: 
    UnCopyable() : ptr(new int) {}
    ~UnCopyable() { delete ptr; }
    UnCopyable(const UnCopyable & other) = delete;
    UnCopyable& operator=(const UnCopyable & other) = delete;
};

请记住,当std::vector需要放大时,它可以重新分配使用的内存。这意味着所有指向元素的迭代器和指针都将失效,无法再使用。因此,保存指向向量元素的指针不是一个好主意。指向向量元素的指针的值旨在在调整向量大小后始终刷新,这是从外部访问向量元素的唯一方法。我计划稍后用地图替换向量,但现在我对这种访问方法还可以,我需要明确地跟踪一个元素。我不确定stl容器是否适合以后使用,但现在这是我的情况。通过“保留地址”,你是在问向量元素是否保持相同的地址?或者它们的指针成员在移动/复制后是否保持相同的值?“…移动每个元素并将地址保留在内存中。”否。我看到元素的内存地址没有保留。我相信现有向量元素的索引是通过向量扩展保留的。i、 e.push_back(超出当前容量)创建一个新的连续分配,并添加一个新索引。但其中涉及许多实施细节。例如:在ubuntu上,使用g++,扩展(由推回引起)会使连续内存加倍。我也想到了这一点。因此,由于我没有显式定义的复制或移动构造函数,因此似乎使用了默认的复制构造函数,它只会将成员变量的值复制到新的内存位置。这似乎是对的?
class UnCopyable
{
    int* ptr;
public: 
    UnCopyable() : ptr(new int) {}
    ~UnCopyable() { delete ptr; }
    UnCopyable(const UnCopyable & other) = delete;
    UnCopyable& operator=(const UnCopyable & other) = delete;
};