• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
2 // test_enable_shared_from_this.cpp
3 
4 // (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
5 // Use, modification and distribution is subject to the Boost Software
6 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8 
9 // This demonstrates a problem with boost::serialization and boost::enable_shared_from_this.
10 // (boost version 1.53)
11 // See boost TRAC ticket #9567
12 //
13 // Given the following class structure:
14 //    Base is a simple class
15 //    Derived inherits from Base
16 //    Derived also inherits from boost::enable_shared_from_this<Derived>
17 //    Base and Derived implement boost::serialization
18 //
19 // When deserializing an instance of Derived into a vector of boost::shared_ptr<Derived>:
20 //    Base and Derived members are reconstructed correctly.
21 //	  Derived::shared_from_this() works as expected.
22 //
23 // But when deserializing an instance of Derived into a vector of boost::shared_ptr<Base>:
24 //    Base and Derived members are still reconstructed correctly.
25 //	  Derived::shared_from_this() throws a bad_weak_ptr exception.
26 //    This is because enable_shared_from_this::weak_ptr is NOT reconstructed - It is zero.
27 
28 #include <sstream>
29 
30 #include <boost/archive/text_oarchive.hpp>
31 #include <boost/archive/text_iarchive.hpp>
32 
33 #include <boost/enable_shared_from_this.hpp>
34 #include <boost/serialization/shared_ptr.hpp>
35 #include <boost/serialization/export.hpp>
36 #include <boost/serialization/split_free.hpp>
37 
38 #include "test_tools.hpp"
39 
40 #include <set>
41 
42 namespace boost {
43 namespace serialization {
44 
45 struct enable_shared_from_this_helper {
46     std::set<shared_ptr<void> > m_esfth;
recordboost::serialization::enable_shared_from_this_helper47     void record(boost::shared_ptr<void>  sp){
48         m_esfth.insert(sp);
49     }
50 };
51 
52 template<class Archive, class T>
serialize(Archive & ar,boost::enable_shared_from_this<T> & t,const unsigned int file_version)53 void serialize(
54     Archive & ar,
55     boost::enable_shared_from_this<T> & t,
56     const unsigned int file_version
57 ){
58     enable_shared_from_this_helper & h =
59         ar.template get_helper<
60             enable_shared_from_this_helper
61         >();
62 
63     shared_ptr<T> sp = t.shared_from_this();
64     h.record(sp);
65 }
66 
67 } // serialization
68 } // boost
69 
70 class Base {
71     friend class boost::serialization::access;
72 
73 	template<class Archive>
serialize(Archive & ar,const unsigned int version)74 	void serialize(Archive & ar, const unsigned int version)
75 	{
76 		ar & BOOST_SERIALIZATION_NVP(m_base);
77 	}
78 protected:
Base()79 	Base() {}
~Base()80 	virtual ~Base() {}		// "virtual" forces RTTI, to enable serialization of Derived from Base pointer
81 public:
82 	int m_base;
83 };
84 
85 class Derived : public Base, public boost::enable_shared_from_this<Derived> {
86     friend class boost::serialization::access;
87 
88 	template<class Archive>
serialize(Archive & ar,const unsigned int version)89 	void serialize(Archive & ar, const unsigned int version)
90 	{
91 		ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base);
92 		ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(
93             boost::enable_shared_from_this<Derived>
94         );
95 		ar & BOOST_SERIALIZATION_NVP(m_derived);
96 	}
97 public:
SharedPtr()98 	boost::shared_ptr<Derived> SharedPtr() { return shared_from_this(); }
99 	int m_derived;
Derived()100 	Derived() {}
~Derived()101 	~Derived() {}
102 };
103 // The following is required to enable serialization from Base pointer
BOOST_CLASS_EXPORT(Derived)104 BOOST_CLASS_EXPORT(Derived)
105 
106 // This test passes
107 void test_passes(){
108 	std::stringstream ss;
109 	{
110 		boost::shared_ptr<Derived> d(new Derived());
111 		d->m_base = 1;
112 		d->m_derived = 2;
113 
114 		// Get a raw pointer to Derived
115 		Derived* raw_d = d.get();
116 
117 		// Verify base and derived members
118 		BOOST_CHECK(raw_d->m_base==1);
119 		BOOST_CHECK(raw_d->m_derived==2);
120 
121 		// verify shared_from_this
122 		BOOST_CHECK(d == raw_d->SharedPtr());
123 
124 		boost::archive::text_oarchive oa(ss);
125 		oa & BOOST_SERIALIZATION_NVP(d);
126 	}
127 	{
128 		// Deserialize it back into a vector of shared_ptr<Derived>
129 		boost::shared_ptr<Derived> d;
130 		ss.seekg(0);
131 		boost::archive::text_iarchive ia(ss);
132 		ia & BOOST_SERIALIZATION_NVP(d);
133 
134 		// Get a raw pointer to Derived
135 		Derived* raw_d = d.get();
136 
137 		// Verify base and derived members
138 		BOOST_CHECK(raw_d->m_base==1);
139 		BOOST_CHECK(raw_d->m_derived==2);
140 
141 		// verify shared_from_this
142 		BOOST_CHECK(d == raw_d->SharedPtr());
143 	}
144 }
145 
146 // This test fails
test_fails()147 void test_fails(){
148 	std::stringstream ss;
149 	{
150 		boost::shared_ptr<Base> b(new Derived());
151 		Derived* raw_d1 = static_cast<Derived*>(b.get());
152 		raw_d1->m_base = 1;
153 		raw_d1->m_derived = 2;
154 
155 		// Get a raw pointer to Derived via shared_ptr<Base>
156 		Derived* raw_d = static_cast<Derived*>(b.get());
157 
158 		// Verify base and derived members
159 		BOOST_CHECK(raw_d->m_base==1);
160 		BOOST_CHECK(raw_d->m_derived==2);
161 
162 		// verify shared_from_this
163 		boost::shared_ptr<Derived> d = raw_d->SharedPtr();
164 		BOOST_CHECK(d == b);
165 		// Serialize the vector
166 		boost::archive::text_oarchive oa(ss);
167 		oa & BOOST_SERIALIZATION_NVP(b);
168 	}
169 	{
170 		// Deserialize it back into a vector of shared_ptr<Base>
171 		ss.seekg(0);
172 		boost::archive::text_iarchive ia(ss);
173 		boost::shared_ptr<Base> b;
174 		ia & BOOST_SERIALIZATION_NVP(b);
175 
176 		// Get a raw pointer to Derived via shared_ptr<Base>
177 		Derived* raw_d = static_cast<Derived*>(b.get());
178 		// Verify base and derived members
179 		BOOST_CHECK(raw_d->m_base==1);
180 		BOOST_CHECK(raw_d->m_derived==2);
181 
182 		// verify shared_from_this
183 		// FAIL: The following line throws bad_weak_ptr exception
184 		boost::shared_ptr<Derived> d = raw_d->SharedPtr();
185 		BOOST_CHECK(d == b);
186 	}
187 }
188 
test_main(int,char * [])189 int test_main(int /*argc*/, char * /*argv */[]){
190     test_fails();
191     test_passes();
192     return EXIT_SUCCESS;
193 }
194 
195 // EOF
196