Home > Back-end >  trying to insert a vector to an unordered_map but get "message : see reference to class templat
trying to insert a vector to an unordered_map but get "message : see reference to class templat

Time:03-17

I'm trying to make an ecs and this is my code

#include "pandaFramework.h"
#include "pandaSystem.h"

#include <unordered_map>
#include <vector>
#include <memory>

#include <iostream>

struct Component {
    NodePath* node_path;
    Component(NodePath* path) {
        node_path = path;
    }
    void start(){}
    void update(){}
};

struct Spinner : Component {
    void update() {
        std::cout << "Hello World!\n";
    }
};

class Scene : public NodePathCollection {
public:
    std::unordered_map<NodePath*, std::vector<std::unique_ptr<Component>>> components;
    void add_path(NodePath node_path) {
        NodePathCollection::add_path(node_path);
        std::vector<std::unique_ptr<Component>> empty;
        components[&node_path] = std::move(empty);
    }

    template<typename ComponentType>
    void add_component(NodePath* node_path) {
        components[node_path].push_back(std::make_unique<ComponentType>(node_path));
    }
};

int main(int argc, char* argv[]) {

    // Load the window and set its title.

    PandaFramework framework;

    framework.open_framework(argc, argv);

    framework.set_window_title("My Panda3D Window");

    WindowFramework* window = framework.open_window();


    // Load the environment model.

    NodePath scene = window->load_model(framework.get_models(), "models/environment");

    Scene s;
    s.add_path(scene);
    s.add_component<Spinner>(&scene);

    // Reparent the model to render.

    scene.reparent_to(window->get_render());

    // Apply scale and position transforms to the model.

    scene.set_scale(0.25f, 0.25f, 0.25f);

    scene.set_pos(-8, 42, 0);


    // Run the engine.

    framework.main_loop();

    // Shut down the engine when done.

    framework.close_framework();

    return 0;

}

And when I use add_object I get
"message : see reference to class template instantiation 'std::vectorstd::unique_ptr<Component,std::default_delete<Component>,std::allocatorstd::unique_ptr<Component,std::default_delete<Component>>>' being compiled"
What should I do?

CodePudding user response:

There are multiple fundamental bugs with the shown code.

You will get the same compilation error with the following code, as well:

std::vector<std::unique_ptr<Component>> empty;
std::vector<std::unique_ptr<Component>> empty2=empty;

A std::unique_ptr, by definition, a one and only pointer to the same underlying object. There are no others. For that reason is why std::unique_ptr does not have a copy constuctor. A std::unique_ptr cannot be copied. This is an absolute rule. No exceptions. The above code attempts to copy a vector of std::unique_ptrs. Since they cannot be copied, this fails. The fact that, in this instance, the vectors are empty is immaterial.

    void add_object(Object object) {
        std::vector<std::unique_ptr<Component>> empty;
        components[&object] = empty;
    }

The assignment operator effectively attempts to make a copy of the vector, and this fails for the same reason.

It's possible to make this work using move semantics:

components[&object] = std::move(empty);

This will now compile. But now you have a different bug to deal with.

object is a parameter to this function.

When this function returns, all of its parameters get destroyed. They will no longer exist. They will cease to exist. They will become no more. They will be come ex-objects.

And the code above will be left with a pointer to a destroyed object in the unordered map. Whatever happens to touch that pointer, from that point on, by definition, will be undefined behavior. You will need to fix this as well.

CodePudding user response:

The problem is very layered, as mentioned in Sam's answer. One problem is that you lack a proper copy constructor for the Component class. This can be solved by not using a temporary variable as shown in the code below:

class Scene {
public:
    std::unordered_map<Object*, std::vector<std::unique_ptr<Component>>> components;
    void add_object(Object object) {
        // std::vector<std::unique_ptr<Component>> empty;
        // Adding an empty container at the given key
        components[&object] = std::vector<std::unique_ptr<Component>>();
    }
};

For the other problems Sam's mentions in his answers, perhaps, instead of using a pointer to an Object, you could use the object instead. This could also lead to the same copy constructor issue, but the code should work with minimal changes.

  • Related