Architecture for manager that gets shared among different components It started with a simple log manager. Then I wanted to implement more features, for example printing the name of the component that send a message. Later on, I can think of giving each component that prints log messages it's own text color in the terminal and options to mute or solo single modules.

Therefore, the manager needs the identity of the component that called its methods. So I decided to wrap the manager with an instance for every component. It tunnels function calls to the manager together with the name of the component.

#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;memory&gt;
#include &lt;unordered_map&gt;
using namespace std;

////////////////////////////////////////////////////////////////
// Manager declaration
////////////////////////////////////////////////////////////////

class manager {
public:
    class instance;

    instance &amp;get_instance(string name);
    void print(string sender, string message);

private:
    unordered_map&lt;string, unique_ptr&lt;instance&gt;&gt; m_instances;
};

////////////////////////////////////////////////////////////////
// Instance declaration
////////////////////////////////////////////////////////////////

class manager::instance {
public:
    instance(string name, manager &amp;manager);
    void print(string message);

private:
    string m_name;
    manager &amp;m_manager;
};

////////////////////////////////////////////////////////////////
// Manager implementation
////////////////////////////////////////////////////////////////

manager::instance &amp;manager::get_instance(string name) {
    if (m_instances.find(name) == m_instances.end())
        m_instances[name] = unique_ptr&lt;instance&gt;(new instance(name, *this));
    return *m_instances[name].get();
}

void manager::print(string sender, string message) {
    cout &lt;&lt; sender &lt;&lt; ": " &lt;&lt; message &lt;&lt; "." &lt;&lt; endl;
}

////////////////////////////////////////////////////////////////
// Instance implementation
////////////////////////////////////////////////////////////////

manager::instance::instance(string name, manager &amp;manager) : m_name(name),
    m_manager(manager) {}

void manager::instance::print(string message) {
    m_manager.print(m_name, message);
}

////////////////////////////////////////////////////////////////
// Main function
////////////////////////////////////////////////////////////////

int main() {
    manager m;
    m.get_instance("Window").print("Open up");
    m.get_instance("Asset").print("Load textures");
    return 0;
}


Here is a working example of my code. What do you think about the class structure and architecture? Is there an easier or more expressive way? I'd like to get feedback and improve the code structure before implementing other managers the same way.
About the architecture and thinking exclusively on the given example application (logging), I believe manager does not need to track all manager::instance instances. Maybe in other applications this might be needed, but not in this one. Thus, I would just turn get_instance into a convenience method (make_instance) to create new manager::instances:

class manager {
public:
    class instance;

    std::unique_ptr&lt;instance&gt; make_instance(const std::string&amp; name);
    void print(const std::string&amp; sender, const std::string&amp; message);
};

std::unique_ptr&lt;manager::instance&gt; manager::make_instance(const std::string&amp; name) {
    return std::unique_ptr&lt;instance&gt;(new instance(name, *this));
}


If you plan using the manager like a singleton (having only one instance and everyone can access it), maybe the manager and manager::instance classes could be merge into a single one, where manager members would become static and manager::instance would become an actual instance of manager.

Please note that both simplifications above may not apply to other applications.

Now, the general code review comments (some of which were already applied on the snippet above):

The code is very well organized, very easy to read and understand. The coding style is consistent. I have only 3 suggestions for improvement:

Always pass std::string to a function as const std::string&amp; instead of just std::string to avoid an unnecessary copy.

Avoid using namespace std;. If, for instance, you really want to use some std symbols unqualified, import them explicitly (like using std::string;). Also avoid using declarations on headers where they may affect user code (in global or namespace scope), otherwise it may break other's code when they include your header.

Also, use braces after if, while, do and for. Those kind of bugs (adding another indented line thinking it inside a block) are hard to spot.