|
Boost Users : |
From: Dima F. (quantera_at_[hidden])
Date: 2007-04-20 07:58:19
Aaron Windsor wrote:
> The predicates used in a filtered_graph can have non-static members.
> In particular, I don't see anything wrong with the example you included
> in your previous email. The predicate needs to be default constructable
> because in the implementation of filtered_graph, it's stored by value in
> an iterator and the iterator must be default constructable. But you can
> still create a non-default instance of your predicate and pass it in to
> filtered_graph and you should get the results you expect - just make
> sure it has the correct semantics when default constructed.
Here is an example which (it seems to me) shows that non-static
members in predicate can cause a problem (see code below). The
program causes segmentation fault, and it happens when pointer to one
of non-static members is dereferenced. When I tried to find the
reason, it seems that a pointer, when used in operator() during
an execution of BFS, contains garbage, that is - it doesn't point
to an object it was pointing to after a predicate object was constructed.
When you run the program, it is possible to see according to a log
messages that sometimes predicate is constructed using a default
constructor, which means that it's members are not copied to a new object.
P.S.: Also, I see that copy-constructor is used, which is somewhat
strange - it is written (http://www.sgi.com/tech/stl/DefaultConstructible.html):
"[1] The form X x = X() is not guaranteed to be a valid expression, because it
uses a copy constructor. A type that is DefaultConstructible is not necessarily
Assignable"
and predicate is only supposed to be Default Constructible, not Assignable...
Test program:
------------------------------------------------------------
#include <set>
#include <iostream>
#include <boost/tuple/tuple.hpp>
#include <boost/graph/filtered_graph.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/breadth_first_search.hpp>
using namespace std;
using namespace boost;
template <typename DistanceMap, typename ParentMap>
class my_bfs_visitor : public default_bfs_visitor {
public:
my_bfs_visitor(DistanceMap &dist, ParentMap &paren)
: m_dist(dist), m_paren(paren) {}
template <typename Edge, typename Graph>
void tree_edge(Edge e, Graph& g) {
m_dist[target(e, g)] = m_dist[source(e, g)] + 1;
m_paren[target(e, g)] = e;
}
private:
DistanceMap &m_dist;
ParentMap &m_paren;
};
template <typename Graph, typename VertexCont>
class induced_graph_filter {
public:
typedef typename graph_traits<Graph>::edge_descriptor edge_t;
typedef typename graph_traits<Graph>::vertex_descriptor vertex_t;
induced_graph_filter()
{ cout << "constructed\n";}
induced_graph_filter(const induced_graph_filter& g)
{
cout << "copy-constructed\n";
m_g = g.m_g;
m_vert = g.m_vert;
}
induced_graph_filter(Graph *g, VertexCont *vert)
: m_g(g), m_vert(vert) {}
induced_graph_filter& operator=(const induced_graph_filter &g)
{
cout << "assigned\n";
m_g = g.m_g;
m_vert = g.m_vert;
}
bool operator()(const vertex_t &v) const {
if (m_vert->find(v) != m_vert->end())
return true;
return false;
}
bool operator()(const edge_t &e) const {
if (m_vert->find(source(e, *m_g)) != m_vert->end() &&
m_vert->find(target(e, *m_g)) != m_vert->end())
{
return true;
}
return false;
}
private:
Graph *m_g;
VertexCont *m_vert;
};
int main() {
typedef adjacency_list <listS, vecS, undirectedS> graph_t;
graph_t g(7);
add_edge(0, 1, g);
add_edge(0, 2, g);
add_edge(1, 2, g);
add_edge(2, 3, g);
add_edge(3, 4, g);
add_edge(3, 5, g);
add_edge(4, 6, g);
add_edge(5, 6, g);
typedef graph_traits<graph_t>::edge_descriptor edge_t;
typedef map<int, int> dist_t;
typedef map<int, edge_t> paren_t;
dist_t dist;
paren_t paren;
my_bfs_visitor<dist_t, paren_t> vis(dist, paren);
cout << "Distances in original graph:\n\n";
breadth_first_search(g, 0, visitor(vis));
for (dist_t::iterator it = dist.begin(); it != dist.end(); it++)
cout << "Distance of " << it->first << " is: " << it->second << endl;
typedef set<int> cont_t;
cont_t cont;
cont.insert(0);
cont.insert(1);
cont.insert(2);
cout << "\nAnd in filtered graph:\n\n";
typedef induced_graph_filter<graph_t, cont_t> filter_t;
filter_t filter(&g, &cont);
filtered_graph<graph_t, filter_t, filter_t> g2(g, filter);
dist.clear();
paren.clear();
breadth_first_search(g2, 0, visitor(vis));
for (dist_t::iterator it = dist.begin(); it != dist.end(); it++)
cout << "Distance of " << it->first << " is: " << it->second << endl;
}
------------------------------------------------------------
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net