You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

游戏引擎组件中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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 19:14:50