std::vector iterators get invalidated at grow

for/release
dmatetelki 11 years ago
parent 6a75b25edb
commit 72630c3d6b

@ -51,8 +51,7 @@ private:
struct Vertex { struct Vertex {
// because of parallell accumulate, ctor(int) is needed and that could conflict Vertex(const_reference data) : m_data(data), m_edges() {}
// Vertex(const_reference data) : m_data(data), m_edges() {}
Vertex() : m_data(), m_edges() {} Vertex() : m_data(), m_edges() {}
Vertex(const Vertex& o) : m_data(o.m_data), m_edges(o.m_edges) {} Vertex(const Vertex& o) : m_data(o.m_data), m_edges(o.m_edges) {}
@ -61,12 +60,12 @@ private:
bool operator==(const Vertex& o) const; bool operator==(const Vertex& o) const;
// parallell accumulate requires both // parallell accumulate requires both
Vertex(int) : Vertex() {} Vertex(size_type) : Vertex() {}
explicit operator int() const { return (int)m_edges.size(); } explicit operator int() const { return (int)m_edges.size(); }
void addEdge(v_iterator destination, const_weight_reference weight = weight_type()); void addEdge(v_const_iterator destination, const_weight_reference weight = weight_type());
void removeEdge(v_iterator destination, const_weight_reference weight = weight_type()); void removeEdge(v_const_iterator destination, const_weight_reference weight = weight_type());
void removeAllEdgesTo(v_iterator destination); void removeAllEdgesTo(v_const_iterator destination);
std::vector<Edge> edges() const; std::vector<Edge> edges() const;
value_type m_data; value_type m_data;
@ -82,6 +81,7 @@ public:
Edge() : source(), destination(), weight() {} Edge() : source(), destination(), weight() {}
Edge(const_reference source, const_reference destination, const_weight_reference weight); Edge(const_reference source, const_reference destination, const_weight_reference weight);
Edge(const Edge& o); Edge(const Edge& o);
~Edge() {}
Edge& operator=(Edge o) { swap(o); return *this; } Edge& operator=(Edge o) { swap(o); return *this; }
void swap(Edge& o); void swap(Edge& o);
bool operator==(const Edge& o) const { return source == o.source && destination == o.destination && weight == o.weight; } bool operator==(const Edge& o) const { return source == o.source && destination == o.destination && weight == o.weight; }
@ -115,6 +115,9 @@ public:
/// @todo rename Vertex & Edge? /// @todo rename Vertex & Edge?
// Modifiers // Modifiers
void reserveVertexCapacity(int c) { m_vertices.reserve(c); }
void clear() { m_vertices.clear(); }
void addVertex(const_reference data); void addVertex(const_reference data);
void removeVertex(const_reference data); void removeVertex(const_reference data);
void addEdge(const_reference source, const_reference destination, const_weight_reference weight = weight_type()); void addEdge(const_reference source, const_reference destination, const_weight_reference weight = weight_type());
@ -220,7 +223,10 @@ private:
v_iterator find(const_reference data); v_iterator find(const_reference data);
v_const_iterator findAndCheck(const_reference data, bool existence_expected = true) const; v_const_iterator findAndCheck(const_reference data, bool existence_expected = true) const;
v_iterator findAndCheck(const_reference data, bool existence_expected = true); v_iterator findAndCheck(const_reference data, bool existence_expected = true);
void adjustEdges(v_iterator vit);
/// @todo make is a vector specializetion
void adjustIteratorsAfter(v_iterator vit);
void resizeVerticesVector();
const bool m_directed; const bool m_directed;
v_container m_vertices; v_container m_vertices;
@ -362,22 +368,25 @@ inline bool Graph<V, E>::Vertex::operator==(const Vertex& other) const
} }
template <typename V, typename E> template <typename V, typename E>
inline void Graph<V, E>::Vertex::addEdge(v_iterator destination, const_weight_reference weight) inline void Graph<V, E>::Vertex::addEdge(v_const_iterator destination, const_weight_reference weight)
{ {
m_edges.push_back(EdgeTo(destination, weight)); m_edges.push_back(EdgeTo(destination, weight));
} }
template <typename V, typename E> template <typename V, typename E>
inline void Graph<V, E>::Vertex::removeEdge(v_iterator destination, const_weight_reference weight) inline void Graph<V, E>::Vertex::removeEdge(v_const_iterator destination, const_weight_reference weight)
{ {
m_edges.erase( typename std::list<EdgeTo>::iterator it =
std::find_if(m_edges.begin(), m_edges.end(), std::find_if(m_edges.begin(), m_edges.end(),
[&destination, &weight](const EdgeTo& e) [&destination, &weight](const EdgeTo& e)
{ return e.m_destination == destination && e.m_weight == weight;})); { return e.m_destination == destination && e.m_weight == weight;});
if (it != m_edges.end())
m_edges.erase(it);
} }
template <typename V, typename E> template <typename V, typename E>
inline void Graph<V, E>::Vertex::removeAllEdgesTo(v_iterator destination) inline void Graph<V, E>::Vertex::removeAllEdgesTo(v_const_iterator destination)
{ {
m_edges.erase( m_edges.erase(
std::remove_if(m_edges.begin(), m_edges.end(), std::remove_if(m_edges.begin(), m_edges.end(),
@ -403,6 +412,7 @@ template <typename V, typename E>
Graph<V, E>::Graph(std::initializer_list<V> vertex_list) Graph<V, E>::Graph(std::initializer_list<V> vertex_list)
: Graph<V, E>() : Graph<V, E>()
{ {
reserveVertexCapacity(vertex_list.size());
for(const V& v : vertex_list) for(const V& v : vertex_list)
addVertex(v); addVertex(v);
} }
@ -411,6 +421,8 @@ template <typename V, typename E>
Graph<V, E>::Graph(std::initializer_list<Edge> edge_list) Graph<V, E>::Graph(std::initializer_list<Edge> edge_list)
: Graph<V, E>() : Graph<V, E>()
{ {
// m_vertices.resize(edge_list.size());
// m_vertices.resize(2);
for (const Edge& e : edge_list ) for (const Edge& e : edge_list )
addEdge(e.source, e.destination, e.weight); addEdge(e.source, e.destination, e.weight);
} }
@ -429,9 +441,10 @@ inline void Graph<V, E>::addVertex(const_reference data)
if (find(data) != m_vertices.end()) if (find(data) != m_vertices.end())
return; return;
Vertex v; if (m_vertices.size() == m_vertices.capacity())
v.m_data = data; resizeVerticesVector();
m_vertices.push_back(v);
m_vertices.push_back(Vertex(data));
} }
template <typename V, typename E> template <typename V, typename E>
@ -446,7 +459,7 @@ inline void Graph<V, E>::removeVertex(const_reference data)
{ v.removeAllEdgesTo(it); } ); { v.removeAllEdgesTo(it); } );
m_vertices.erase(it); m_vertices.erase(it);
adjustEdges(it); adjustIteratorsAfter(it);
} }
template <typename V, typename E> template <typename V, typename E>
@ -474,9 +487,9 @@ inline void Graph<V, E>::removeEdge(const_reference source, const_reference dest
if (destination_it == m_vertices.end()) if (destination_it == m_vertices.end())
return; return;
source_it->removeEdge(destination, weight); source_it->removeEdge(destination_it, weight);
if (!m_directed) if (!m_directed)
destination_it->removeEdge(source, weight); destination_it->removeEdge(source_it, weight);
} }
template <typename V, typename E> template <typename V, typename E>
@ -571,7 +584,7 @@ Graph<V, E>::find(const_reference data)
} }
template <typename V, typename E> template <typename V, typename E>
void Graph<V, E>::adjustEdges(v_iterator deleted_vit) void Graph<V, E>::adjustIteratorsAfter(v_iterator deleted_vit)
{ {
std::for_each(m_vertices.begin(), m_vertices.end(), std::for_each(m_vertices.begin(), m_vertices.end(),
[&deleted_vit](Vertex& v) [&deleted_vit](Vertex& v)
@ -581,5 +594,24 @@ void Graph<V, E>::adjustEdges(v_iterator deleted_vit)
}); });
} }
template <typename V, typename E>
void Graph<V, E>::resizeVerticesVector()
{
const float grow_factor = 1.5;
const int old_size = m_vertices.size();
const int new_size = old_size == 0 ? 1 : old_size * grow_factor + 0.5;
std::vector<value_type> old_vertices = vertices();
std::vector<Edge> old_edges = edges();
clear();
reserveVertexCapacity(new_size);
for(auto v: old_vertices)
addVertex(v);
for(auto e: old_edges)
addEdge(e.source, e.destination, e.weight);
}
#endif // GRAPH_H #endif // GRAPH_H

Loading…
Cancel
Save