Fix double-destruction problem with small function objects and swap(), and try to work around a GCC 4.2 issue. See #1910 for comments about the former problem from Niels Dekker.

[SVN r48627]
This commit is contained in:
Douglas Gregor
2008-09-06 03:16:25 +00:00
parent f379ef8532
commit 2fe4cc253f
3 changed files with 59 additions and 11 deletions

View File

@ -99,12 +99,12 @@ namespace boost {
// For pointers to std::type_info objects
struct type_t {
// (get_functor_type_tag, check_functor_type_tag).
const std::type_info* type;
const BOOST_FUNCTION_STD_NS::type_info* type;
// Whether the type is const-qualified.
bool const_qualified : 1;
bool const_qualified;
// Whether the type is volatile-qualified.
bool volatile_qualified : 1;
bool volatile_qualified;
} type;
// For function pointers of all kinds
@ -120,8 +120,8 @@ namespace boost {
// track of the cv-qualifiers on the object referenced.
struct obj_ref_t {
mutable void* obj_ptr;
bool is_const : 1;
bool is_volatile : 1;
bool is_const_qualified;
bool is_volatile_qualified;
} obj_ref;
// To relax aliasing constraints
@ -217,9 +217,9 @@ namespace boost {
// Check whether we have the same type. We can add
// cv-qualifiers, but we can't take them away.
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(F))
&& (!in_buffer.obj_ref.is_const
&& (!in_buffer.obj_ref.is_const_qualified
|| out_buffer.type.const_qualified)
&& (!in_buffer.obj_ref.is_volatile
&& (!in_buffer.obj_ref.is_volatile_qualified
|| out_buffer.type.volatile_qualified))
out_buffer.obj_ptr = in_buffer.obj_ref.obj_ptr;
else
@ -229,8 +229,8 @@ namespace boost {
case get_functor_type_tag:
out_buffer.type.type = &typeid(F);
out_buffer.type.const_qualified = in_buffer.obj_ref.is_const;
out_buffer.type.volatile_qualified = in_buffer.obj_ref.is_volatile;
out_buffer.type.const_qualified = in_buffer.obj_ref.is_const_qualified;
out_buffer.type.volatile_qualified = in_buffer.obj_ref.is_volatile_qualified;
return;
}
}

View File

@ -517,8 +517,8 @@ namespace boost {
{
if (!boost::detail::function::has_empty_target(f.get_pointer())) {
functor.obj_ref.obj_ptr = (void *)f.get_pointer();
functor.obj_ref.is_const = is_const<FunctionObj>::value;
functor.obj_ref.is_volatile = is_volatile<FunctionObj>::value;
functor.obj_ref.is_const_qualified = is_const<FunctionObj>::value;
functor.obj_ref.is_volatile_qualified = is_volatile<FunctionObj>::value;
return true;
} else {
return false;
@ -801,6 +801,7 @@ namespace boost {
this->vtable = f.vtable;
f.vtable->manager(f.functor, this->functor,
boost::detail::function::move_functor_tag);
f.vtable = 0;
#if !defined(BOOST_NO_EXCEPTIONS)
} else {
clear();

View File

@ -636,6 +636,52 @@ test_ref()
}
}
static unsigned construction_count = 0;
static unsigned destruction_count = 0;
struct MySmallFunctor {
MySmallFunctor() { ++construction_count; }
MySmallFunctor(const MySmallFunctor &) { ++construction_count; }
~MySmallFunctor() { ++destruction_count; }
int operator()() { return 0; }
};
struct MyLargeFunctor {
MyLargeFunctor() { ++construction_count; }
MyLargeFunctor(const MyLargeFunctor &) { ++construction_count; }
~MyLargeFunctor() { ++destruction_count; }
int operator()() { return 0; }
};
void test_construct_destroy_count()
{
{
boost::function0<int> f;
boost::function0<int> g;
f = MySmallFunctor();
g = MySmallFunctor();
f.swap(g);
}
// MySmallFunctor objects should be constructed as many times as
// they are destroyed.
BOOST_CHECK(construction_count == destruction_count);
construction_count = 0;
destruction_count = 0;
{
boost::function0<int> f;
boost::function0<int> g;
f = MyLargeFunctor();
g = MyLargeFunctor();
f.swap(g);
}
// MyLargeFunctor objects should be constructed as many times as
// they are destroyed.
BOOST_CHECK(construction_count == destruction_count);
}
int test_main(int, char* [])
{
test_zero_args();
@ -644,5 +690,6 @@ int test_main(int, char* [])
test_emptiness();
test_member_functions();
test_ref();
test_construct_destroy_count();
return 0;
}