Fixed memleak for CoordinateType/BoundingObject which have throwing copy constructor for R*tree.

Added comments regarding exception-safety.

[SVN r81438]
This commit is contained in:
Adam Wulkiewicz
2012-11-20 17:00:41 +00:00
parent e2beb3cf2f
commit 7ed71e5324
6 changed files with 68 additions and 62 deletions

View File

@@ -1,6 +1,6 @@
// Boost.Geometry Index
//
// Spatial query predicates
// Nonassignable base class.
//
// Copyright (c) 2011-2012 Adam Wulkiewicz, Lodz, Poland.
//

View File

@@ -133,6 +133,8 @@ public:
m_size = 0;
}
// IMPORTANT!
// The sequence of elements is NOT preserved
inline void erase(iterator it)
{
BOOST_GEOMETRY_INDEX_ASSERT(0 < m_size, "there are no elements in the container");

View File

@@ -224,7 +224,7 @@ struct redistribute_elements<Value, Options, Translator, Box, Allocators, linear
BOOST_GEOMETRY_INDEX_ASSERT(elements1.size() == elements1_count, "unexpected number of elements");
// copy original elements
elements_type elements_copy(elements1); // MAY THROW
elements_type elements_copy(elements1); // MAY THROW, STRONG (alloc, copy)
// calculate initial seeds
size_t seed1 = 0;
@@ -242,8 +242,8 @@ struct redistribute_elements<Value, Options, Translator, Box, Allocators, linear
try
{
// add seeds
elements1.push_back(elements_copy[seed1]); // MAY THROW
elements2.push_back(elements_copy[seed2]); // MAY THROW
elements1.push_back(elements_copy[seed1]); // MAY THROW, STRONG (copy)
elements2.push_back(elements_copy[seed2]); // MAY THROW, STRONG (alloc, copy)
// calculate boxes
geometry::convert(rtree::element_indexable(elements_copy[seed1], translator), box1);
@@ -268,13 +268,13 @@ struct redistribute_elements<Value, Options, Translator, Box, Allocators, linear
// just insert them to this node
if ( elements1.size() + remaining <= parameters.get_min_elements() )
{
elements1.push_back(elem); // MAY THROW
elements1.push_back(elem); // MAY THROW, STRONG (copy)
geometry::expand(box1, indexable);
content1 = index::content(box1);
}
else if ( elements2.size() + remaining <= parameters.get_min_elements() )
{
elements2.push_back(elem); // MAY THROW
elements2.push_back(elem); // MAY THROW, STRONG (alloc, copy)
geometry::expand(box2, indexable);
content2 = index::content(box2);
}
@@ -297,13 +297,13 @@ struct redistribute_elements<Value, Options, Translator, Box, Allocators, linear
( content_increase1 == content_increase2 && content1 < content2 ) ||
( content1 == content2 && elements1.size() <= elements2.size() ) )
{
elements1.push_back(elem); // MAY THROW
elements1.push_back(elem); // MAY THROW, STRONG (copy)
box1 = enlarged_box1;
content1 = enlarged_content1;
}
else
{
elements2.push_back(elem); // MAY THROW
elements2.push_back(elem); // MAY THROW, STRONG (alloc, copy)
box2 = enlarged_box2;
content2 = enlarged_content2;
}
@@ -322,7 +322,7 @@ struct redistribute_elements<Value, Options, Translator, Box, Allocators, linear
rtree::destroy_elements<Value, Options, Translator, Box, Allocators>::apply(elements_copy, allocators);
//elements_copy.clear();
throw; // RETHROW
throw; // RETHROW, BASIC
}
}
};

View File

@@ -109,8 +109,8 @@ struct redistribute_elements<Value, Options, Translator, Box, Allocators, quadra
BOOST_GEOMETRY_INDEX_ASSERT(elements1.size() == elements1_count, "unexpected elements number");
// copy original elements
elements_type elements_copy(elements1); // MAY THROW
elements_type elements_backup(elements1); // MAY THROW
elements_type elements_copy(elements1); // MAY THROW, STRONG (alloc, copy)
elements_type elements_backup(elements1); // MAY THROW, STRONG (alloc, copy)
// calculate initial seeds
size_t seed1 = 0;
@@ -129,8 +129,8 @@ struct redistribute_elements<Value, Options, Translator, Box, Allocators, quadra
try
{
// add seeds
elements1.push_back(elements_copy[seed1]); // MAY THROW
elements2.push_back(elements_copy[seed2]); // MAY THROW
elements1.push_back(elements_copy[seed1]); // MAY THROW, STRONG (copy)
elements2.push_back(elements_copy[seed2]); // MAY THROW, STRONG (alloc, copy)
// calculate boxes
geometry::convert(rtree::element_indexable(elements_copy[seed1], translator), box1);
@@ -139,13 +139,13 @@ struct redistribute_elements<Value, Options, Translator, Box, Allocators, quadra
// remove seeds
if (seed1 < seed2)
{
elements_copy.erase(elements_copy.begin() + seed2); // MAY THROW
elements_copy.erase(elements_copy.begin() + seed1); // MAY THROW
elements_copy.erase(elements_copy.begin() + seed2); // MAY THROW, BASIC (copy)
elements_copy.erase(elements_copy.begin() + seed1); // MAY THROW, BASIC (copy)
}
else
{
elements_copy.erase(elements_copy.begin() + seed1); // MAY THROW
elements_copy.erase(elements_copy.begin() + seed2); // MAY THROW
elements_copy.erase(elements_copy.begin() + seed1); // MAY THROW, BASIC (copy)
elements_copy.erase(elements_copy.begin() + seed2); // MAY THROW, BASIC (copy)
}
// initialize areas
@@ -201,20 +201,20 @@ struct redistribute_elements<Value, Options, Translator, Box, Allocators, quadra
if ( insert_into_group1 )
{
elements1.push_back(elem); // MAY THROW
elements1.push_back(elem); // MAY THROW, STRONG (copy)
geometry::expand(box1, indexable);
content1 = index::content(box1);
}
else
{
elements2.push_back(elem); // MAY THROW
elements2.push_back(elem); // MAY THROW, STRONG (alloc, copy)
geometry::expand(box2, indexable);
content2 = index::content(box2);
}
BOOST_GEOMETRY_INDEX_ASSERT(!elements_copy.empty(), "expected more elements");
typename elements_type::iterator el_it_base = el_it.base();
elements_copy.erase(--el_it_base); // MAY THROW
elements_copy.erase(--el_it_base); // MAY THROW, BASIC (copy)
BOOST_GEOMETRY_INDEX_ASSERT(0 < remaining, "expected more remaining elements");
--remaining;
@@ -229,7 +229,7 @@ struct redistribute_elements<Value, Options, Translator, Box, Allocators, quadra
rtree::destroy_elements<Value, Options, Translator, Box, Allocators>::apply(elements_backup, allocators);
//elements_backup.clear();
throw; // RETHROW
throw; // RETHROW, BASIC
}
}

View File

@@ -68,11 +68,11 @@ struct choose_split_axis_and_index_for_corner
BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == parameters.get_max_elements() + 1, "wrong number of elements");
// copy elements
Elements elements_copy(elements); // MAY THROW
Elements elements_copy(elements); // MAY THROW, STRONG (alloc, copy)
// sort elements
element_axis_corner_less<element_type, Translator, Corner, AxisIndex> elements_less(translator);
std::sort(elements_copy.begin(), elements_copy.end(), elements_less); // MAY THROW
std::sort(elements_copy.begin(), elements_copy.end(), elements_less); // MAY THROW, BASIC (copy)
// init outputs
choosen_index = parameters.get_min_elements();
@@ -135,7 +135,7 @@ struct choose_split_axis_and_index_for_axis<Parameters, Box, AxisIndex, box_tag>
choose_split_axis_and_index_for_corner<Parameters, Box, min_corner, AxisIndex>::
apply(elements, index1,
som1, ovl1, con1,
parameters, translator); // MAY THROW
parameters, translator); // MAY THROW, STRONG
size_t index2 = 0;
margin_type som2 = 0;
@@ -145,7 +145,7 @@ struct choose_split_axis_and_index_for_axis<Parameters, Box, AxisIndex, box_tag>
choose_split_axis_and_index_for_corner<Parameters, Box, max_corner, AxisIndex>::
apply(elements, index2,
som2, ovl2, con2,
parameters, translator); // MAY THROW
parameters, translator); // MAY THROW, STRONG
sum_of_margins = som1 + som2;
@@ -185,7 +185,7 @@ struct choose_split_axis_and_index_for_axis<Parameters, Box, AxisIndex, point_ta
choose_split_axis_and_index_for_corner<Parameters, Box, min_corner, AxisIndex>::
apply(elements, choosen_index,
sum_of_margins, smallest_overlap, smallest_content,
parameters, translator); // MAY THROW
parameters, translator); // MAY THROW, STRONG
choosen_corner = min_corner;
}
@@ -215,7 +215,7 @@ struct choose_split_axis_and_index
choose_split_axis_and_index<Parameters, Box, Dimension - 1>::
apply(elements, choosen_axis, choosen_corner, choosen_index,
smallest_sum_of_margins, smallest_overlap, smallest_content,
parameters, translator); // MAY THROW
parameters, translator); // MAY THROW, STRONG
margin_type sum_of_margins = 0;
@@ -230,7 +230,7 @@ struct choose_split_axis_and_index
Box,
Dimension - 1,
typename index::traits::tag<element_indexable_type>::type
>::apply(elements, corner, index, sum_of_margins, overlap_val, content_val, parameters, translator); // MAY THROW
>::apply(elements, corner, index, sum_of_margins, overlap_val, content_val, parameters, translator); // MAY THROW, STRONG
if ( sum_of_margins < smallest_sum_of_margins )
{
@@ -284,7 +284,7 @@ struct partial_sort
{
if ( axis < Dimension - 1 )
{
partial_sort<Corner, Dimension - 1>::apply(elements, axis, index, tr); // MAY THROW
partial_sort<Corner, Dimension - 1>::apply(elements, axis, index, tr); // MAY THROW, BASIC (copy)
}
else
{
@@ -292,7 +292,7 @@ struct partial_sort
typedef typename Elements::value_type element_type;
element_axis_corner_less<element_type, Translator, Corner, Dimension - 1> less(tr);
std::partial_sort(elements.begin(), elements.begin() + index, elements.end(), less); // MAY THROW
std::partial_sort(elements.begin(), elements.begin() + index, elements.end(), less); // MAY THROW, BASIC (copy)
}
}
};
@@ -307,7 +307,7 @@ struct partial_sort<Corner, 1>
typedef typename Elements::value_type element_type;
element_axis_corner_less<element_type, Translator, Corner, 0> less(tr);
std::partial_sort(elements.begin(), elements.begin() + index, elements.end(), less); // MAY THROW
std::partial_sort(elements.begin(), elements.begin() + index, elements.end(), less); // MAY THROW, BASIC (copy)
}
};
@@ -356,7 +356,7 @@ struct redistribute_elements<Value, Options, Translator, Box, Allocators, rstar_
>::apply(elements1,
split_axis, split_corner, split_index,
smallest_sum_of_margins, smallest_overlap, smallest_content,
parameters, translator); // MAY THROW
parameters, translator); // MAY THROW, STRONG
// TODO: awulkiew - get rid of following static_casts?
@@ -365,23 +365,24 @@ struct redistribute_elements<Value, Options, Translator, Box, Allocators, rstar_
BOOST_GEOMETRY_INDEX_ASSERT(parameters.get_min_elements() <= split_index && split_index <= parameters.get_max_elements() - parameters.get_min_elements() + 1, "unexpected value");
// copy original elements
elements_type elements_copy(elements1); // MAY THROW
elements_type elements_copy(elements1); // MAY THROW, STRONG
elements_type elements_backup(elements1); // MAY THROW, STRONG
// TODO: awulkiew - check if std::partial_sort produces the same result as std::sort
if ( split_corner == static_cast<size_t>(min_corner) )
rstar::partial_sort<min_corner, dimension>
::apply(elements_copy, split_axis, split_index, translator); // MAY THROW
::apply(elements_copy, split_axis, split_index, translator); // MAY THROW, BASIC (copy)
else
rstar::partial_sort<max_corner, dimension>
::apply(elements_copy, split_axis, split_index, translator); // MAY THROW
::apply(elements_copy, split_axis, split_index, translator); // MAY THROW, BASIC (copy)
try
{
// copy elements to nodes
elements1.resize(split_index); // MIGHT THROW
std::copy(elements_copy.begin(), elements_copy.begin() + split_index, elements1.begin()); // MAY THROW
elements2.resize(parameters.get_max_elements() + 1 - split_index); // MAY THROW
std::copy(elements_copy.begin() + split_index, elements_copy.end(), elements2.begin()); // MAY THROW
elements1.resize(split_index); // SHOULDN'T THROW
std::copy(elements_copy.begin(), elements_copy.begin() + split_index, elements1.begin()); // MAY THROW, BASIC
elements2.resize(parameters.get_max_elements() + 1 - split_index); // MAY THROW, STRONG
std::copy(elements_copy.begin() + split_index, elements_copy.end(), elements2.begin()); // MAY THROW, BASIC
// calculate boxes
box1 = rtree::elements_box<Box>(elements1.begin(), elements1.end(), translator);
@@ -389,13 +390,14 @@ struct redistribute_elements<Value, Options, Translator, Box, Allocators, rstar_
}
catch(...)
{
//elements_copy.clear();
elements1.clear();
elements2.clear();
rtree::destroy_elements<Value, Options, Translator, Box, Allocators>::apply(elements_copy, allocators);
//elements_copy.clear();
rtree::destroy_elements<Value, Options, Translator, Box, Allocators>::apply(elements_backup, allocators);
//elements_backup.clear();
throw; // RETHROW
throw; // RETHROW, BASIC
}
}
};

View File

@@ -157,7 +157,7 @@ public:
Box,
Allocators,
typename Options::redistribute_tag
>::apply(n, n2, n_box, box2, parameters, translator, allocators); // MAY THROW (V: alloc, copy, E: alloc)
>::apply(n, n2, n_box, box2, parameters, translator, allocators); // MAY THROW (V, E: alloc, copy, copy)
// check numbers of elements
BOOST_GEOMETRY_INDEX_ASSERT(parameters.get_min_elements() <= rtree::elements(n).size() &&
@@ -168,7 +168,7 @@ public:
"unexpected number of elements");
// return the list of newly created nodes (this algorithm returns one)
additional_nodes.push_back(std::make_pair(box2, second_node.get())); // MAY THROW
additional_nodes.push_back(std::make_pair(box2, second_node.get())); // MAY THROW (alloc, copy)
// release the ptr
second_node.release();
@@ -269,7 +269,7 @@ protected:
rtree::element_indexable(m_element, m_translator));
// next traversing step
traverse_apply_visitor(visitor, n, choosen_node_index); // MAY THROW (V: alloc, copy, E: alloc, N:alloc)
traverse_apply_visitor(visitor, n, choosen_node_index); // MAY THROW, BASIC (V, E: alloc, copy, N:alloc)
}
// TODO: awulkiew - change post_traverse name to handle_overflow or overflow_treatment?
@@ -284,7 +284,7 @@ protected:
// handle overflow
if ( m_parameters.get_max_elements() < rtree::elements(n).size() )
{
split(n); // MAY THROW (V: alloc, copy, E: alloc, N:alloc)
split(n); // MAY THROW, BASIC (V, E: alloc, copy, N:alloc)
}
}
@@ -298,7 +298,7 @@ protected:
m_traverse_data.move_to_next_level(&n, choosen_node_index);
// next traversing step
rtree::apply_visitor(visitor, *rtree::elements(n)[choosen_node_index].second); // MAY THROW (V: alloc, copy, E: alloc, N:alloc)
rtree::apply_visitor(visitor, *rtree::elements(n)[choosen_node_index].second); // MAY THROW, BASIC (V, E: alloc, copy, N:alloc)
// restore previous traverse inputs
m_traverse_data = backup_traverse_data;
@@ -314,11 +314,12 @@ protected:
typename split_algo::nodes_container_type additional_nodes;
Box n_box;
split_algo::apply(additional_nodes, n, n_box, m_parameters, m_translator, m_allocators); // MAY THROW (V: alloc, copy, E: alloc, N:alloc)
split_algo::apply(additional_nodes, n, n_box, m_parameters, m_translator, m_allocators); // MAY THROW, BASIC (V, E: alloc, copy, N:alloc)
BOOST_GEOMETRY_INDEX_ASSERT(additional_nodes.size() == 1, "unexpected number of additional nodes");
// TODO add all additional nodes
// For kmeans algorithm:
// elements number may be greater than node max elements count
// split and reinsert must take node with some elements count
// and container of additional elements (std::pair<Box, node*>s or Values)
@@ -336,7 +337,7 @@ protected:
// update old node's box
m_traverse_data.current_element().first = n_box;
// add new node to parent's children
m_traverse_data.parent_elements().push_back(additional_nodes[0]); // MAY THROW (V: alloc, copy, E: alloc)
m_traverse_data.parent_elements().push_back(additional_nodes[0]); // MAY THROW, STRONG (V, E: alloc, copy)
}
// node is the root - add level
else
@@ -344,15 +345,15 @@ protected:
BOOST_GEOMETRY_INDEX_ASSERT(&n == rtree::get<Node>(m_root_node), "node should be the root");
// create new root and add nodes
node_auto_ptr new_root(rtree::create_node<Allocators, internal_node>::apply(m_allocators), m_allocators); // MAY THROW (N:alloc)
node_auto_ptr new_root(rtree::create_node<Allocators, internal_node>::apply(m_allocators), m_allocators); // MAY THROW, STRONG (N:alloc)
try {
rtree::elements(rtree::get<internal_node>(*new_root)).push_back(std::make_pair(n_box, m_root_node)); // MAY THROW (E:alloc)
rtree::elements(rtree::get<internal_node>(*new_root)).push_back(additional_nodes[0]); // MAY THROW (E:alloc)
rtree::elements(rtree::get<internal_node>(*new_root)).push_back(std::make_pair(n_box, m_root_node)); // MAY THROW, STRONG (E:alloc, copy)
rtree::elements(rtree::get<internal_node>(*new_root)).push_back(additional_nodes[0]); // MAY THROW, STRONG (E:alloc, copy)
} catch (...) {
// clear new root to not delete in the ~node_auto_ptr() potentially stored old root node
rtree::elements(rtree::get<internal_node>(*new_root)).clear();
throw; // RETHROW
throw; // RETHROW, BASIC
}
m_root_node = new_root.get();
@@ -421,7 +422,7 @@ public:
if ( base::m_traverse_data.current_level < base::m_level )
{
// next traversing step
base::traverse(*this, n); // MAY THROW (E: alloc, N: alloc)
base::traverse(*this, n); // MAY THROW, BASIC (E: alloc, copy, N: alloc)
}
else
{
@@ -430,19 +431,20 @@ public:
try
{
// push new child node
rtree::elements(n).push_back(base::m_element); // MAY THROW (E: alloc)
rtree::elements(n).push_back(base::m_element); // MAY THROW, STRONG (E: alloc, copy)
}
catch(...)
{
// if the insert fails here, the element won't be stored in the tree
// if the insert fails above, the element won't be stored in the tree
rtree::visitors::destroy<Value, Options, Translator, Box, Allocators> del_v(base::m_element.second, base::m_allocators);
rtree::apply_visitor(del_v, *base::m_element.second);
throw; // RETHROW
throw; // RETHROW, BASIC
}
}
base::post_traverse(n); // MAY THROW (E: alloc, N: alloc)
base::post_traverse(n); // MAY THROW, BASIC (E: alloc, copy, N: alloc)
}
inline void operator()(leaf &)
@@ -481,9 +483,9 @@ public:
BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_level, "unexpected level");
// next traversing step
base::traverse(*this, n); // MAY THROW (V: alloc, copy, E: alloc, N: alloc)
base::traverse(*this, n); // MAY THROW, BASIC (V, E: alloc, copy, N: alloc)
base::post_traverse(n); // MAY THROW (E: alloc, N: alloc)
base::post_traverse(n); // MAY THROW, BASIC (E: alloc, copy, N: alloc)
}
inline void operator()(leaf & n)
@@ -492,9 +494,9 @@ public:
BOOST_GEOMETRY_INDEX_ASSERT(base::m_level == base::m_traverse_data.current_level ||
base::m_level == (std::numeric_limits<size_t>::max)(), "unexpected level");
rtree::elements(n).push_back(base::m_element); // MAY THROW (V: alloc, copy)
rtree::elements(n).push_back(base::m_element); // MAY THROW, STRONG (V: alloc, copy)
base::post_traverse(n); // MAY THROW (V: alloc, copy, E: alloc, N: alloc)
base::post_traverse(n); // MAY THROW, BASIC (V: alloc, copy, N: alloc)
}
};