游戏引擎组件中std::map内的setter函数为何无法正确赋值?
问题原因
你的代码存在两个核心问题导致属性无法被正确修改:
- Lambda捕获的
this指向已销毁的临时对象:std::vector<Transform> ts = {Transform()};会先创建一个临时Transform对象,再将其拷贝到vector的元素中。而Transform构造函数里的Lambda用[=]值捕获了临时对象的this指针,临时对象在拷贝完成后立即销毁。后续调用setter时,实际修改的是已销毁临时对象的x,而非vector中真实存在的Transform实例。 - 默认拷贝构造的隐患:即使跳过临时对象,默认拷贝构造函数会直接拷贝
_setters,但拷贝后的Lambda仍然指向原对象的this,若原对象被销毁,同样会出现无效指针问题。
修复方案
提供两种可靠的修复方式,可根据业务场景选择:
方案1:避免临时对象拷贝,直接在vector中构造组件
修改main函数的vector初始化逻辑,用emplace_back直接在vector内存中构造Transform,跳过临时对象的创建与拷贝步骤:
int main() { std::vector<Transform> ts; ts.emplace_back(); // 直接在vector内存中构造Transform,无临时对象 Component* c = &ts[0]; c->_setters["x"](3.0); std::cout << ts[0].x << std::endl; // 输出3.0 return 0; }
同时将Transform构造函数的Lambda捕获改为显式的[this](比[=]更清晰,避免捕获歧义):
Transform() { _setters["x"] = [this](Property p){this->__set_x(p); }; }
方案2:自定义拷贝构造函数,确保拷贝后组件持有正确的setter
如果业务逻辑需要支持组件拷贝,需给Transform自定义拷贝构造函数,重新初始化_setters,让拷贝后的组件Lambda指向自身的this:
class Transform : public Component { // ... 原有代码 ... // 自定义拷贝构造函数 Transform(const Transform& other) : Component(other), x(other.x) { // 重新初始化setter,捕获当前对象的this _setters["x"] = [this](Property p){this->__set_x(p); }; } // 可选:定义移动构造函数以支持移动语义 Transform(Transform&& other) noexcept : Component(std::move(other)), x(other.x) { _setters["x"] = [this](Property p){this->__set_x(p); }; } };
这样即使通过临时对象拷贝创建vector元素,拷贝后的Transform的setter也会正确指向自身,修改的是当前实例的属性。
额外建议
- 若后续要支持多组件类型,建议改用
vector<std::unique_ptr<Component>>存储基类指针,避免对象切片和拷贝带来的问题。 - 尽量用
[this]显式捕获当前对象指针,比[=]更清晰,减少捕获歧义。
内容的提问来源于stack exchange,提问作者MusicalRoc
相关产品推荐
相关产品推荐

