如何在GameObject类的Collider成员中存储Transform引用并访问修改?
问题分析与解决方案
你碰到的核心问题是:当把GameObject对象存入vector时,vector扩容会触发对象的拷贝/移动,导致Collider中存储的Transform指针指向已销毁的旧对象,自然无法修改当前GameObject的Transform。
原因拆解
你的代码里,GameObject的构造函数初始化Collider时用&this->transform是没问题的——因为类成员的初始化顺序是按声明顺序来的,transform先声明会先初始化,之后collider再拿它的地址是安全的。但main里把GameObject对象push_back到vector时,如果vector容量不够,会重新分配内存,把旧元素挪到新地址,原来的Transform成员地址就失效了,Collider里的指针就成了野指针。
解决方案1:用智能指针存GameObject,避免对象拷贝
把vector的元素类型改成unique_ptr<GameObject>,让GameObject始终在堆上,地址固定,Collider里的指针永远有效:
#include <vector> #include <memory> struct Transform{ float x, y; Transform(float x_, float y_) : x(x_), y(y_) {} }; class Collider{ public: Transform* transform; Collider(Transform* _transform) : transform(_transform) {} // 示例:碰撞后更新Transform的方法 void updateOnCollision() { if (transform) { transform->x += 1.0f; transform->y += 1.0f; } } }; class GameObject{ public: Transform transform; Collider collider; GameObject(Transform t) : transform(t), collider(&this->transform) {} }; int main(){ std::vector<std::unique_ptr<GameObject>> quads; for(int i=0; i<10; i++){ quads.push_back(std::make_unique<GameObject>(Transform(i*2.0f, i*3.0f))); } // 测试修改Transform quads[0]->collider.updateOnCollision(); }
解决方案2:自定义拷贝/移动函数,同步更新Collider的指针
如果一定要用值类型存GameObject,就得在拷贝、移动构造和赋值运算符里,让新对象的Collider指向自身的Transform:
#include <vector> #include <utility> // 用于std::move struct Transform{ float x, y; Transform(float x_, float y_) : x(x_), y(y_) {} }; class Collider{ public: Transform* transform; Collider(Transform* _transform) : transform(_transform) {} // 拷贝构造 Collider(const Collider& other) : transform(other.transform) {} // 移动构造 Collider(Collider&& other) noexcept : transform(other.transform) { other.transform = nullptr; } // 拷贝赋值 Collider& operator=(const Collider& other) { if (this != &other) transform = other.transform; return *this; } // 移动赋值 Collider& operator=(Collider&& other) noexcept { if (this != &other) { transform = other.transform; other.transform = nullptr; } return *this; } void updateOnCollision() { if (transform) { transform->x += 1.0f; transform->y += 1.0f; } } }; class GameObject{ public: Transform transform; Collider collider; GameObject(Transform t) : transform(t), collider(&this->transform) {} // 拷贝构造:让新对象的collider指向自己的transform GameObject(const GameObject& other) : transform(other.transform), collider(&this->transform) {} // 移动构造:同样指向自身的transform GameObject(GameObject&& other) noexcept : transform(std::move(other.transform)), collider(&this->transform) {} // 拷贝赋值 GameObject& operator=(const GameObject& other) { if (this != &other) { transform = other.transform; collider.transform = &this->transform; } return *this; } // 移动赋值 GameObject& operator=(GameObject&& other) noexcept { if (this != &other) { transform = std::move(other.transform); collider.transform = &this->transform; } return *this; } }; int main(){ std::vector<GameObject> quads; for(int i=0; i<10; i++){ quads.push_back(GameObject(Transform(i*2.0f, i*3.0f))); } quads[0].collider.updateOnCollision(); }
解决方案3:动态分配Transform,保持地址不变
用shared_ptr管理Transform,这样就算GameObject被拷贝/移动,Transform的地址也不会变:
#include <vector> #include <memory> struct Transform{ float x, y; Transform(float x_, float y_) : x(x_), y(y_) {} }; class Collider{ public: std::shared_ptr<Transform> transform; Collider(std::shared_ptr<Transform> _transform) : transform(_transform) {} void updateOnCollision() { if (transform) { transform->x += 1.0f; transform->y += 1.0f; } } }; class GameObject{ public: std::shared_ptr<Transform> transform; Collider collider; GameObject(Transform t) : transform(std::make_shared<Transform>(t)), collider(transform) {} }; int main(){ std::vector<GameObject> quads; for(int i=0; i<10; i++){ quads.push_back(GameObject(Transform(i*2.0f, i*3.0f))); } quads[0].collider.updateOnCollision(); }
内容的提问来源于stack exchange,提问作者Seon Il
相关产品推荐
相关产品推荐

