|
Boost : |
From: Howard Hinnant (howard.hinnant_at_[hidden])
Date: 2006-03-17 14:17:55
Sorry for the delay in the follow up.
On Mar 16, 2006, at 7:03 PM, Peter Dimov wrote:
> Can you try the +m change on as many g++ versions as possible? I
> may be
> misremembering things. Or can you try the potentially safer
> alternative of
> adding "m"( *pw ) as an input and see whether this also works?
Yes, that seems to work just fine too.
>
> If you contribute your test case, this will be appreciated, too.
The original report was one of the boost unit tests:
---- file boost_unit_test_gcc4_pb_sample.cpp ---
#include <iostream>
#include <boost/test/unit_test.hpp>
using boost::unit_test_framework::test_suite;
using boost::unit_test_framework::test_case;
using namespace std;
class SampleTest {
public:
SampleTest (int val) :
a (val)
{
}
int a;
void sampleTest ()
{
std::cout << "a : " << a << std::endl;
BOOST_CHECK_EQUAL (a, 12345);
}
};
test_suite*
init_unit_test_suite( int argc, char* argv[] )
{
test_suite* test= BOOST_TEST_SUITE( "Sample test" );
boost::shared_ptr<SampleTest> instance (new SampleTest (12345));
test->add (BOOST_CLASS_TEST_CASE ( & SampleTest::sampleTest,
instance));
return test;
}
---- end-of-file boost_unit_test_gcc4_pb_sample.cpp ---
The symptom showed itself by having the SampleTest destructor (or
malloc) scribble on destructed/deleted memory.
I later narrowed it down to that included below. Sorry, it is kind
of big. I never did reduce it further.
#include <boost/shared_ptr.hpp>
namespace boost {
namespace ut_detail {
struct unused {};
template<typename R>
struct invoker {
template<typename Functor>
R invoke( Functor& f ) { return f(); }
template<typename Functor, typename T1>
R invoke( Functor& f, T1 t1 ) { return f( t1 ); }
template<typename Functor, typename T1, typename T2>
R invoke( Functor& f, T1 t1, T2 t2 ) { return f( t1, t2 ); }
template<typename Functor, typename T1, typename T2, typename T3>
R invoke( Functor& f, T1 t1, T2 t2, T3 t3 ) { return f( t1, t2,
t3 ); }
};
template<>
struct invoker<unused> {
template<typename Functor>
unused invoke( Functor& f ) { f(); return unused(); }
template<typename Functor, typename T1>
unused invoke( Functor& f, T1 t1 ) { f( t1 ); return unused(); }
template<typename Functor, typename T1, typename T2>
unused invoke( Functor& f, T1 t1, T2 t2 ) { f( t1, t2 ); return
unused(); }
template<typename Functor, typename T1, typename T2, typename T3>
unused invoke( Functor& f, T1 t1, T2 t2, T3 t3 ) { f( t1, t2,
t3 ); return unused(); }
};
}
namespace ut_detail {
template<typename R>
struct callback0_impl {
virtual ~callback0_impl() {}
virtual R invoke() = 0;
};
template<typename R, typename Functor>
struct callback0_impl_t : callback0_impl<R> {
explicit callback0_impl_t( Functor f ) : m_f( f ) {}
virtual R invoke() { return invoker<R>().invoke( m_f ); }
private:
Functor m_f;
};
template<typename R = void>
class callback0 {
public:
callback0() {}
template<typename Functor>
callback0( Functor f )
: m_impl( new ut_detail::callback0_impl_t<R,Functor>( f ) ) {}
void operator=( callback0 const& rhs ) { m_impl = rhs.m_impl; }
template<typename Functor>
void operator=( Functor f ) { m_impl.reset( new
ut_detail::callback0_impl_t<R,Functor>( f ) ); }
R operator()() const { return m_impl->invoke(); }
bool operator!() const { return !m_impl; }
private:
boost::shared_ptr<ut_detail::callback0_impl<R> > m_impl;
};
class test_case {
public:
enum { type = 1 };
test_case( callback0<> const& test_func );
callback0<> const& test_func() const { return m_test_func; }
private:
friend class framework_impl;
~test_case() {}
callback0<> m_test_func;
};
inline
test_case::test_case( callback0<> const& test_func )
: m_test_func( test_func )
{
}
}
namespace ut_detail {
template<typename UserTestCase>
struct user_tc_method_invoker {
typedef void (UserTestCase::*test_method )();
user_tc_method_invoker( shared_ptr<UserTestCase> inst,
test_method tm )
: m_inst( inst ), m_test_method( tm ) {}
void operator()() { ((*m_inst).*m_test_method)(); }
shared_ptr<UserTestCase> m_inst;
test_method m_test_method;
};
}
template<typename UserTestCase>
ut_detail::test_case*
make_test_case( void (UserTestCase::*test_method )(),
boost::shared_ptr<UserTestCase> const&
user_test_case )
{
return new ut_detail::test_case
( ut_detail::user_tc_method_invoker<UserTestCase>( user_test_case,
test_method ) );
}
}
class SampleTest {
public:
SampleTest (int val) :
a (val)
{
}
int a;
void sampleTest ()
{
}
};
SampleTest* g;
int
main()
{
boost::ut_detail::test_case* t;
{
boost::shared_ptr<SampleTest> instance (g = new SampleTest (12345));
std::cout << "instance.use_count = " << instance.use_count() << "
before add: g = " << g << " *g = " << g->a << '\n';
t = boost::make_test_case((& SampleTest::sampleTest), instance );
std::cout << "instance.use_count = " << instance.use_count() << "
after add: g = " << g << " *g = " << g->a << '\n';
}
std::cout << "after add: g = " << g << " *g = " << g->a << '\n';
return t != 0;
}
expecting an output similar to:
instance.use_count = 1 before add: g = 0x30010 *g = 12345
instance.use_count = 2 after add: g = 0x30010 *g = 12345
after add: g = 0x30010 *g = 12345
The use_count values were the dead giveaway. The second one was
coming out 1 or even sometimes 0.
-Howard
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk