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

搭建ECS架构时触发std::unique_ptr删除函数错误,求排查方案

问题分析与解决:ECS架构中Scene拷贝赋值编译错误

问题背景

正在搭建基础的Entity Component System(ECS)架构,已定义如下类:

class Component
{
public:
    virtual ~Component() {};  // Ensure polymorphic behavior with a virtual destructor
};

class TransformComponent : public Component
{
    glm::vec2 position = {0.0f, 0.0f};
    float rotation = 0.0f;
    float scale = 1.0f;
};

using identifier =  uuids::uuid;
class Entity {
private:
    identifier id;
    bool isActive = true;
    std::string name = "new entity";

    std::vector<std::unique_ptr<Component>> components;
public:
    Entity() : isActive(true), id( UUID::get()), name("NEW") {};
    ~Entity() = default;

    // Disable copying
    Entity(const Entity&) = delete;
    Entity& operator=(const Entity&) = delete;

    // Define move constructor and move assignment
    Entity(Entity&& other) noexcept;
    Entity& operator=(Entity&& other) noexcept;

    template<typename T>
    T* GetOrAdd() {
        static_assert(std::is_base_of<Component, T>::value, "T must be derived from Component");
        for (auto& comp : components) {
            if (auto result = dynamic_cast<T*>(comp.get())) {
                return result;
            }
        }
        auto newComp = std::make_unique<T>();
        T* result = newComp.get();
        components.push_back(std::move(newComp));
        return result;
    }
};

在Scene类中以std::unique_ptr<Entity>形式添加实体:

class Scene {
public:
    Scene(std::string sceneName, bool isEditorMode);
    ~Scene();
private: 
    std::unique_ptr<Entity> ent = std::make_unique<Entity>();
};

在HierarchyPanel构造函数中执行currentScene = *GlobalHelper::GetScenes()[0];时,出现如下编译错误:

D:\Projects\searchengineproject\vocabulary\game\src\rendering\HierarchyPanel.cpp: In constructor 'gl3::HierarchyPanel::HierarchyPanel()':
D:\Projects\searchengineproject\vocabulary\game\src\rendering\HierarchyPanel.cpp:9:52: error: use of deleted function 'gl3::Scene& gl3::Scene::operator=(const gl3::Scene&)'
    9 |         currentScene = *GlobalHelper::GetScenes()[0];
      |                                                    ^
In file included from D:\Projects\searchengineproject\vocabulary\game\src\rendering\HierarchyPanel.h:4,
                 from D:\Projects\searchengineproject\vocabulary\game\src\rendering\HierarchyPanel.cpp:1:
D:/Projects/searchengineproject/vocabulary/game/src/entities/Scene.h:21:11: note: 'gl3::Scene& gl3::Scene::operator=(const gl3::Scene&)' is implicitly deleted because the default definition would be ill-formed:
   21 |     class Scene {
      |           ^~~~~
D:/Projects/searchengineproject/vocabulary/game/src/entities/Scene.h:21:11: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>& std::unique_ptr<_Tp, _Dp>::operator=(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = gl3::Entity; _Dp = std::default_delete<gl3::Entity>]'
In file included from D:/Program Files/CLion 2022.3.3/bin/mingw/lib/gcc/x86_64-w64-mingw32/11.2.0/include/c++/bits/locale_conv.h:41,
                 from D:/Program Files/CLion 2022.3.3/bin/mingw/lib/gcc/x86_64-w64-mingw32/11.2.0/include/c++/locale:43,
                 from D:/Program Files/CLion 2022.3.3/bin/mingw/lib/gcc/x86_64-w64-mingw32/11.2.0/include/c++/bits/fs_path.h:37,
                 from D:/Program Files/CLion 2022.3.3/bin/mingw/lib/gcc/x86_64-w64-mingw32/11.2.0/include/c++/filesystem:45,
                 from D:/Projects/searchengineproject/vocabulary/game/src/rendering/Texture.h:6,
                 from D:/Projects/searchengineproject/VokabelTrainer/game/src/GlobalHelper.h:3,
                 from D:\Projects\searchengineproject\vocabulary\game\src\rendering\HierarchyPanel.h:3,
                 from D:\Projects\searchengineproject\vocabulary\game\src\rendering\HierarchyPanel.cpp:1:
D:/Program Files/CLion 2022.3.3/bin/mingw/lib/gcc/x86_64-w64-mingw32/11.2.0/include/c++/bits/unique_ptr.h:469:19: note: declared here
  469 |       unique_ptr& operator=(const unique_ptr&) = delete;
      |                   ^~~~~~~~
mingw32-make[3]: *** [game\CMakeFiles\game_lab_3.dir\build.make:316: game/CMakeFiles/game_lab_3.dir/src/rendering/HierarchyPanel.cpp.obj] Error 1
mingw32-make[3]: *** Waiting for unfinished jobs....
mingw32-make[2]: *** [CMakeFiles\Makefile2:2095: game/CMakeFiles/game_lab_3.dir/all] Error 2
mingw32-make[1]: *** [CMakeFiles\Makefile2:2102: game/CMakeFiles/game_lab_3.dir/rule] Error 2
mingw32-make: *** [Makefile:1047: game_lab_3] Error 2

已查阅类似问题,解决方案均提及避免使用拷贝构造函数,且已在Entity类中禁用拷贝构造与赋值,声明了移动构造和赋值。请问还遗漏了什么?


错误原因

编译错误的核心是Scene类的拷贝赋值运算符被隐式删除:Scene类包含std::unique_ptr<Entity>成员,而std::unique_ptr本身是不可拷贝的(其拷贝赋值运算符被显式删除),因此编译器无法为Scene生成默认的拷贝构造和拷贝赋值函数。你仅处理了Entity类的移动语义,但Scene类的拷贝/移动语义未做处理,代码中currentScene = *GlobalHelper::GetScenes()[0];是在尝试拷贝赋值Scene对象,触发了被删除的拷贝赋值运算符。

解决方案

根据需求,有两种常见处理方式:

方式1:使用指针/引用代替对象拷贝

避免直接拷贝Scene对象,让currentScene持有Scene的指针或引用:

// 修改HierarchyPanel中currentScene的类型为指针
Scene* currentScene;
// 构造函数中改为
currentScene = GlobalHelper::GetScenes()[0];

或使用引用(需确保引用的Scene对象生命周期始终有效):

// 修改HierarchyPanel中currentScene的类型为引用
Scene& currentScene;
// 在构造函数初始化列表中初始化
HierarchyPanel::HierarchyPanel() : currentScene(*GlobalHelper::GetScenes()[0]) {}

方式2:为Scene类实现移动语义

若需要转移Scene的所有权,可为Scene类添加移动构造和移动赋值运算符,允许通过移动而非拷贝传递Scene:

class Scene {
public:
    Scene(std::string sceneName, bool isEditorMode);
    ~Scene();

    // 显式禁用拷贝
    Scene(const Scene&) = delete;
    Scene& operator=(const Scene&) = delete;

    // 启用默认移动构造和赋值
    Scene(Scene&& other) noexcept = default;
    Scene& operator=(Scene&& other) noexcept = default;
private: 
    std::unique_ptr<Entity> ent = std::make_unique<Entity>();
};

之后可通过移动操作赋值:

// 使用std::move转移所有权
currentScene = std::move(*GlobalHelper::GetScenes()[0]);

注意:移动后原Scene对象的ent成员会变为空,需确保后续代码不再使用原对象的无效成员。


内容的提问来源于stack exchange,提问作者notfynnaf

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 09:50:56