1
\$\begingroup\$

I am attempting to create a fast & robust object management system that allows adding, removing and retrieving objects from a "scene". I am trying to wrap my head around the best way to do this regarding ownership and object lifecycle. Code:

main.cpp:

int main()
{
    r3d::scene main_scene;

    game_object& obj = main_scene.create_object("obj", glm::vec3(0, 0, 0), glm::vec3(-90, 0, -90), glm::vec3(1, 1, 1));

    main_scene.remove_object("obj");

    return 0;
}

scene.hpp:

namespace r3d
{
    class scene
    {
    public:
        scene::scene() { }

        game_object& create_object(std::string name,
                                glm::vec3 position = glm::vec3(0, 0, 0),
                                glm::vec3 euler_angles = glm::vec3(0, 0, 0),
                                glm::vec3 scale = glm::vec3(1, 1, 1));

        void remove_object(std::string);

        game_object& get_object(std::string);

    private:
        std::map<std::string, r3d::game_object> game_objects;
    };
}

scene.cpp:

game_object& scene::create_object(std::string name, glm::vec3 position, glm::vec3 euler_angles, glm::vec3 scale)
{
    game_objects.emplace(name, game_object { name, position, euler_angles, scale });

    return game_objects[name];
}

void scene::remove_object(std::string name)
{
    game_objects.erase(name);
}

game_object& scene::get_object(std::string name)
{
    return game_objects[name];
}

game_object.hpp

namespace r3d
{
    class game_object
    {
    public:
        std::string name;

        game_object() {}

        // constructor
        game_object(std::string name, glm::vec3 position, glm::vec3 euler_angles, glm::vec3 scale) 
            : name(name), 
            position(position), 
            euler_angles(euler_angles), 
            scale(scale) 
        {
            printf("New game_object: %s [address: %p]\n", name.c_str(), this);
        }

        // destructor
        ~game_object()
        {
            printf("Delete game_object: %s [address: %p]\n", name.c_str(), this);
        }

        // copy constructor
        game_object(const game_object& source)
            : name { source.name },
            position { source.position },
            euler_angles { source.euler_angles },
            scale { source.scale }
        {
            printf("Copy game_object: %s [from: %p  to: %p]\n", source.name.c_str(), &source, this);
        }

        // move constructor
        game_object(game_object&& source)
            : name { source.name },
            position { source.position },
            euler_angles { source.euler_angles },
            scale { source.scale }
        {
            printf("Move game_object: %s [from: %p  to: %p]\n", source.name.c_str(), &source, this);
        }

    protected:
        glm::vec3 position;
        glm::vec3 euler_angles;
        glm::vec3 scale;
    };
}
\$\endgroup\$
  • 3
    \$\begingroup\$ Do you really want to use pointers here (even smart)? can't you deal with inplace object and references? Also, did you tried std::map or std::unordered_map (with name as a key) instead of a std::set? Can't you emplace the game_object ? \$\endgroup\$ – Calak Dec 4 '18 at 15:46
  • 1
    \$\begingroup\$ Responding to those questions might help people to provide good reviews. \$\endgroup\$ – Calak Dec 8 '18 at 14:37
  • \$\begingroup\$ Thanks for pointing (xD) me in the right direction, was under the assumption that it’s good practice to use pointers to all objects in cpp. After doing some more research I have improved my solution (edited above). \$\endgroup\$ – zooooom Dec 21 '18 at 16:31
  • \$\begingroup\$ Please add the relevant #includes to the code listings and make sure your code compiles and runs correctly. I'd be surprised if this compiles, since std::map operator[] requires a default constructor and game_object doesn't have one. \$\endgroup\$ – user673679 Dec 21 '18 at 17:07
  • 1
    \$\begingroup\$ Your code is essentially a wrapper around a dictionary. What is your use-case for string lookup of the objects? If it's configuration-file-based, then fine. But if there are no exterior files expected to refer to objects, and this is intended for static code only, then I don't understand how this approach benefits you. \$\endgroup\$ – Reinderien Dec 21 '18 at 17:15
1
\$\begingroup\$

the idea being that any other class can access a game_object by name if given a reference to main_scene, even if it doesn't hold a reference to the actual object

You've stated that one of your primary goals is speed. Based on your description above, you can still achieve object lookup and avoid the performance hit of a string dictionary.

One of the easiest ways to do this is to add a header file to the application that defines an enum of numeric, sequential object IDs. This will allow for much faster lookup, and depending on how you define and load your data, you wouldn't even need a map - simply a fixed array.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.