
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