Extreme use of pointers in adjacency list graph construction? Playing around with pointers in C++, implemented an adjacency list graph.
Am I going too far/extreme trying to place data onto the heap?
graph.h
#include &lt;memory&gt;
#include &lt;unordered_map&gt;
#include &lt;forward_list&gt;
#include &lt;utility&gt;

template &lt;typename TKey, typename TWeight&gt;
class Graph{

    struct Adjacent {
        TKey key;
        TWeight weight;
        Adjacent(const TKey key, const TWeight weight): key(key), weight(weight) {};
    };

    struct Vertex {
        TKey value;
        std::unique_ptr&lt;std::forward_list&lt;Adjacent&gt;&gt; adjVertexList;
        explicit Vertex(const TKey value){
            this-&gt;value = value;
            adjVertexList = std::make_unique&lt;std::forward_list&lt;Adjacent&gt;&gt;();
        }
    };

private:
    // Since keys can be non-numeric,
    // use a hashmap to index into individual adj lists
    std::unordered_map&lt;TKey, std::unique_ptr&lt;Vertex&gt;&gt; vertices;

public:
    void addVertex(TKey value);

    // Everything other than addDirectedEdge is just for a nicer API
    void addDirectedEdge(TKey src, TKey dst, TWeight weight);
    void addUndirectedEdge(TKey src, TKey dst, TWeight weight);
    void addDirectedEdge(TKey src, TKey dst);
    void addUndirectedEdge(TKey src, TKey dst);

};

graph.cpp
#include &lt;stdexcept&gt;
#include &quot;graph.h&quot;

template &lt;typename TKey, typename TWeight&gt;
void Graph&lt;TKey, TWeight&gt;::addVertex(TKey value) {
    vertices.insert(std::make_pair(value, std::make_unique&lt;Vertex&gt;(value)));
}

template &lt;typename TKey, typename TWeight&gt;
void Graph&lt;TKey, TWeight&gt;::addDirectedEdge(TKey src, TKey dst, TWeight weight) {

    auto srcPtr = vertices.find(src);

    if(srcPtr == vertices.end())
        throw std::invalid_argument(&quot;Cannot find source&quot;);
    else if(vertices.find(dst) == vertices.end())
        throw std::invalid_argument(&quot;Cannot find destination&quot;);

    Vertex* vertex = srcPtr-&gt;second.get();
    vertex-&gt;adjVertexList-&gt;push_front(Adjacent(dst, weight));

}

template &lt;typename TKey, typename TWeight&gt;
void Graph&lt;TKey, TWeight&gt;::addUndirectedEdge(TKey src, TKey dst, TWeight weight) {
    addDirectedEdge(src, dst, weight);
    addDirectedEdge(dst, src, weight);
}

template &lt;typename TKey, typename TWeight&gt;
void Graph&lt;TKey, TWeight&gt;::addDirectedEdge(TKey src, TKey dst) {
    addDirectedEdge(src, dst, 0);
}

template &lt;typename TKey, typename TWeight&gt;
void Graph&lt;TKey, TWeight&gt;::addUndirectedEdge(TKey src, TKey dst){
    addUndirectedEdge(src, dst, 0);
}
```
Am I going too far/extreme trying to place data onto the heap?

Yes. Containers like std::unordered_map and std::forward_list already store contents on the heap. If you declare a std::unordered_map on the stack, only a little bit of administrative data goes on the stack. But the same happens with std::unique_ptr. So in your code, the use of std::unique_ptr is superfluous and only increases indirection, which might be bad for performance. So just write:
template &lt;typename TKey, typename TWeight&gt;
class Graph {
    ...
    struct Vertex {
        ...
        std::forward_list&lt;Adjacent&gt; adjVertexList;
        ...
    };
    ...
    std::unordered_map&lt;TKey, Vertex&gt; vertices;
    ...
};