Search code examples
c++boostgraphshared-ptrobject-slicing

Is boost graph slicing my shared_ptr


I'm using an implementation of a boost graph with a boost::shared_ptr<Obj> as an edge attribute. I have two class Obj and Obj2 such that:

class Obj{
    public:
    Obj(){};
    virtual func(){std::cout << "Obj func " << std::endl};
};

class Obj2: public Obj{
    public:
    Obj2(){};
    virtual func(){std::cout << "Obj2 func " << std::endl};
};

I'm adding edges in the graph using a (simplified) function such as:

void addEdge(Vertex index, Vertex index2, const boost::shared_ptr<Obj>& edgeAttribute){
    out = boost::add_edge(index, index2, edgeAttribute, graph).first;
}

That I call using :

Obj2* obj = new Obj2();
boost::shared_ptr<Obj2> obj_ptr(obj);
addEdge(index, index2, obj_ptr);

However later in my code when picking up the edge attribute by doing edgeAttr = graph[edge] and then calling the function edgeAttr->func(), I call Obj's func and not Obj2's.

As far as I understand, it means that somewhere my Objects are being sliced. Is this short example I gave supposed to slice my object when using boost:shared_ptr and BGL, or is it some other implementation problem of my own like the initialisation?


Solution

  • No the graph model does not slice any attribute (note, that "attribute" is actually called a bundled property).

    In fact, it does never copy the Obj or Obj2 because it just copies the shared_ptr<> leading to shared ownership, as opposed to copying a property.

    Let's Demonstrate How It Works

    Live On Coliru

    #include <boost/graph/adjacency_list.hpp>
    #include <boost/shared_ptr.hpp>
    #include <boost/make_shared.hpp>
    #include <iostream>
    
    class Obj {
      public:
        Obj(){};
        virtual void func(std::ostream& os) { os << "Obj  func\n"; };
    };
    
    class Obj2 : public Obj {
      public:
        Obj2(){};
        virtual void func(std::ostream& os) { os << "Obj2 func\n"; };
    };
    // I'm adding edges in the graph using a (simplified) function such as:
    
    using Graph = boost::adjacency_list<boost::vecS, boost::vecS,
          boost::directedS, boost::no_property, boost::shared_ptr<Obj> >;
    using Vertex = Graph::vertex_descriptor;
    
    struct Program {
        Program() : _graph(10) {}
    
        void addEdge(Vertex index, Vertex index2, const boost::shared_ptr<Obj> &edgeAttribute) {
            auto out = boost::add_edge(index, index2, edgeAttribute, _graph).first;
        }
    
        void sample_edges() {
            Obj2 *obj = new Obj2();
            boost::shared_ptr<Obj2> obj_ptr(obj);
    
            addEdge(1, 2, boost::make_shared<Obj2>());
            addEdge(2, 3, boost::make_shared<Obj >());
            addEdge(3, 4, boost::make_shared<Obj2>());
            addEdge(4, 5, boost::make_shared<Obj >());
            addEdge(5, 6, boost::make_shared<Obj2>());
            addEdge(6, 7, boost::make_shared<Obj >());
        }
    
        void debug_dump() const {
            for (auto ed : boost::make_iterator_range(boost::edges(_graph))) {
                _graph[ed]->func(std::cout << "Edge " << ed << ": ");
            }
        }
    
      private:
        Graph _graph;
    };
    
    int main() {
        std::cout << "Demo edges:\n";
        Program demo;
        demo.sample_edges();
        demo.debug_dump();
    
        std::cout << "Copied edges:\n";
        // copy the whole shebang
        Program clone = demo;
        clone.debug_dump();
    }
    

    Prints:

    Demo edges:
    Edge (1,2): Obj2 func
    Edge (2,3): Obj  func
    Edge (3,4): Obj2 func
    Edge (4,5): Obj  func
    Edge (5,6): Obj2 func
    Edge (6,7): Obj  func
    Copied edges:
    Edge (1,2): Obj2 func
    Edge (2,3): Obj  func
    Edge (3,4): Obj2 func
    Edge (4,5): Obj  func
    Edge (5,6): Obj2 func
    Edge (6,7): Obj  func