shared_ptr_test.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Peter Dimov 2002-2005, 2007.
  4. // (C) Copyright Ion Gaztanaga 2006-2012.
  5. // Distributed under the Boost Software License, Version 1.0.
  6. // (See accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. //
  9. // See http://www.boost.org/libs/interprocess for documentation.
  10. //
  11. //////////////////////////////////////////////////////////////////////////////
  12. #include <boost/interprocess/detail/config_begin.hpp>
  13. #include <boost/interprocess/offset_ptr.hpp>
  14. #include <boost/interprocess/smart_ptr/shared_ptr.hpp>
  15. #include <boost/interprocess/smart_ptr/weak_ptr.hpp>
  16. #include <boost/interprocess/smart_ptr/enable_shared_from_this.hpp>
  17. #include <boost/interprocess/managed_shared_memory.hpp>
  18. #include <boost/interprocess/allocators/allocator.hpp>
  19. #include <boost/interprocess/containers/string.hpp>
  20. #include <boost/interprocess/containers/vector.hpp>
  21. #include <boost/interprocess/smart_ptr/deleter.hpp>
  22. #include <boost/interprocess/smart_ptr/scoped_ptr.hpp>
  23. #include <boost/core/lightweight_test.hpp>
  24. #include <string>
  25. #include "get_process_id_name.hpp"
  26. #include <boost/interprocess/sync/upgradable_lock.hpp>
  27. #include <boost/interprocess/sync/interprocess_upgradable_mutex.hpp>
  28. using namespace boost::interprocess;
  29. class base_class
  30. {
  31. public:
  32. virtual ~base_class()
  33. {}
  34. };
  35. class derived_class
  36. : public base_class
  37. {
  38. public:
  39. virtual ~derived_class()
  40. {}
  41. };
  42. int simple_test()
  43. {
  44. typedef managed_shared_memory::segment_manager segment_mngr_t;
  45. typedef allocator<base_class, segment_mngr_t> base_class_allocator;
  46. typedef deleter<base_class, segment_mngr_t> base_deleter_t;
  47. typedef shared_ptr<base_class, base_class_allocator, base_deleter_t> base_shared_ptr;
  48. std::string process_name;
  49. test::get_process_id_name(process_name);
  50. shared_memory_object::remove(process_name.c_str());
  51. {
  52. managed_shared_memory shmem(create_only, process_name.c_str(), 10000);
  53. {
  54. base_shared_ptr s_ptr(base_shared_ptr::pointer(0),
  55. base_class_allocator(shmem.get_segment_manager()),
  56. base_deleter_t(shmem.get_segment_manager()));
  57. base_shared_ptr s_ptr2(shmem.construct<base_class>("base_class")(),
  58. base_class_allocator(shmem.get_segment_manager()),
  59. base_deleter_t(shmem.get_segment_manager()));
  60. base_shared_ptr s_ptr3(offset_ptr<derived_class>(shmem.construct<derived_class>("derived_class")()),
  61. base_class_allocator(shmem.get_segment_manager()),
  62. base_deleter_t(shmem.get_segment_manager()));
  63. if(s_ptr3.get_deleter() == 0){
  64. return 1;
  65. }
  66. //if(s_ptr3.get_allocator() == 0){
  67. //return 1;
  68. //}
  69. base_shared_ptr s_ptr_empty;
  70. if(s_ptr_empty.get_deleter() != 0){
  71. return 1;
  72. }
  73. //if(s_ptr_empty.get_allocator() != 0){
  74. //return 1;
  75. //}
  76. }
  77. }
  78. shared_memory_object::remove(process_name.c_str());
  79. return 0;
  80. }
  81. int string_shared_ptr_vector_insertion_test()
  82. {
  83. typedef managed_shared_memory::segment_manager segment_mngr_t;
  84. //Allocator of chars
  85. typedef allocator<char, segment_mngr_t> char_allocator_t;
  86. //A shared memory string class
  87. typedef basic_string<char, std::char_traits<char>, char_allocator_t> string_t;
  88. //A shared memory string allocator
  89. typedef allocator<string_t, segment_mngr_t> string_allocator_t;
  90. //A deleter for shared_ptr<> that erases a shared memory string
  91. typedef deleter<string_t, segment_mngr_t> string_deleter_t;
  92. //A shared pointer that points to a shared memory string and its instantiation
  93. typedef shared_ptr<string_t, string_allocator_t, string_deleter_t> string_shared_ptr_t;
  94. //An allocator for shared pointers to a string in shared memory
  95. typedef allocator<string_shared_ptr_t, segment_mngr_t> string_shared_ptr_allocator_t;
  96. //A weak pointer that points to a shared memory string and its instantiation
  97. typedef weak_ptr<string_t, string_allocator_t, string_deleter_t> string_weak_ptr_t;
  98. //An allocator for weak pointers to a string in shared memory
  99. typedef allocator<string_weak_ptr_t, segment_mngr_t > string_weak_ptr_allocator_t;
  100. //A vector of shared pointers to strings (all in shared memory) and its instantiation
  101. typedef vector<string_shared_ptr_t, string_shared_ptr_allocator_t>
  102. string_shared_ptr_vector_t;
  103. //A vector of weak pointers to strings (all in shared memory) and its instantiation
  104. typedef vector<string_weak_ptr_t, string_weak_ptr_allocator_t>
  105. string_weak_ptr_vector_t;
  106. std::string process_name;
  107. test::get_process_id_name(process_name);
  108. //A shared memory managed memory classes
  109. shared_memory_object::remove(process_name.c_str());
  110. {
  111. managed_shared_memory shmem(create_only, process_name.c_str(), 20000);
  112. {
  113. const int NumElements = 100;
  114. //Construct the allocator of strings
  115. string_allocator_t string_allocator(shmem.get_segment_manager());
  116. //Construct the allocator of a shared_ptr to string
  117. string_shared_ptr_allocator_t string_shared_ptr_allocator(shmem.get_segment_manager());
  118. //Construct the allocator of a shared_ptr to string
  119. string_weak_ptr_allocator_t string_weak_ptr_allocator(shmem.get_segment_manager());
  120. //This is a string deleter using destroy_ptr() function of the managed_shared_memory
  121. string_deleter_t deleter(shmem.get_segment_manager());
  122. //Create a string in shared memory, to avoid leaks with exceptions use
  123. //scoped ptr until we store this pointer in the shared ptr
  124. scoped_ptr<string_t, string_deleter_t> scoped_string
  125. (shmem.construct<string_t>(anonymous_instance)(string_allocator), deleter);
  126. //Now construct a shared pointer to a string
  127. string_shared_ptr_t string_shared_ptr (scoped_string.get(),
  128. string_shared_ptr_allocator,
  129. deleter);
  130. //Check use count is just one
  131. if(!string_shared_ptr.unique()){
  132. return 1;
  133. }
  134. //We don't need the scoped_ptr anonymous since the raw pointer is in the shared ptr
  135. scoped_string.release();
  136. //Now fill a shared memory vector of shared_ptrs to a string
  137. string_shared_ptr_vector_t my_sharedptr_vector(string_shared_ptr_allocator);
  138. my_sharedptr_vector.insert(my_sharedptr_vector.begin(), NumElements, string_shared_ptr);
  139. //Insert in the middle to test movability
  140. my_sharedptr_vector.insert(my_sharedptr_vector.begin() + my_sharedptr_vector.size()/2, NumElements, string_shared_ptr);
  141. //Now check the shared count is the objects contained in the
  142. //vector plus string_shared_ptr
  143. if(string_shared_ptr.use_count() != static_cast<long>(my_sharedptr_vector.size()+1)){
  144. return 1;
  145. }
  146. //Now create a weak ptr from the shared_ptr
  147. string_weak_ptr_t string_weak_ptr (string_shared_ptr);
  148. //Use count should remain the same
  149. if(string_weak_ptr.use_count() != static_cast<long>(my_sharedptr_vector.size()+1)){
  150. return 1;
  151. }
  152. //Now reset the local shared_ptr and check use count
  153. string_shared_ptr.reset();
  154. if(string_weak_ptr.use_count() != static_cast<long>(my_sharedptr_vector.size())){
  155. return 1;
  156. }
  157. //Now reset the local shared_ptr's use count should be zero
  158. if(string_shared_ptr.use_count() != 0){
  159. return 1;
  160. }
  161. //Now recreate the shared ptr from the weak ptr
  162. //and recheck use count
  163. string_shared_ptr = string_shared_ptr_t(string_weak_ptr);
  164. if(string_shared_ptr.use_count() != static_cast<long>(my_sharedptr_vector.size()+1)){
  165. return 1;
  166. }
  167. //Now fill a vector of weak_ptr-s
  168. string_weak_ptr_vector_t my_weakptr_vector(string_weak_ptr_allocator);
  169. my_weakptr_vector.insert(my_weakptr_vector.begin(), NumElements, string_weak_ptr);
  170. //The shared count should remain the same
  171. if(string_shared_ptr.use_count() != static_cast<long>(my_sharedptr_vector.size()+1)){
  172. return 1;
  173. }
  174. //So weak pointers should be fine
  175. string_weak_ptr_vector_t::iterator beg = my_weakptr_vector.begin(),
  176. end = my_weakptr_vector.end();
  177. for(;beg != end; ++beg){
  178. if(beg->expired()){
  179. return 1;
  180. }
  181. //The shared pointer constructed from weak ptr should
  182. //be the same as the original, since all weak pointer
  183. //point the the same object
  184. if(string_shared_ptr_t(*beg) != string_shared_ptr){
  185. return 1;
  186. }
  187. }
  188. //Now destroy all the shared ptr-s of the shared ptr vector
  189. my_sharedptr_vector.clear();
  190. //The only alive shared ptr should be the local one
  191. if(string_shared_ptr.use_count() != 1){
  192. return 1;
  193. }
  194. //Now we invalidate the last alive shared_ptr
  195. string_shared_ptr.reset();
  196. //Now all weak pointers should have expired
  197. beg = my_weakptr_vector.begin();
  198. end = my_weakptr_vector.end();
  199. for(;beg != end; ++beg){
  200. if(!beg->expired()){
  201. return 1;
  202. }
  203. bool success = false;
  204. //Now this should throw
  205. try{
  206. string_shared_ptr_t dummy(*beg);
  207. //We should never reach here
  208. return 1;
  209. }
  210. catch(const boost::interprocess::bad_weak_ptr &){
  211. success = true;
  212. }
  213. if(!success){
  214. return 1;
  215. }
  216. }
  217. //Clear weak ptr vector
  218. my_weakptr_vector.clear();
  219. //Now lock returned shared ptr should return null
  220. if(string_weak_ptr.lock().get()){
  221. return 1;
  222. }
  223. //Reset weak_ptr
  224. string_weak_ptr.reset();
  225. }
  226. }
  227. shared_memory_object::remove(process_name.c_str());
  228. return 0;
  229. }
  230. //
  231. // This part is taken from shared_ptr_basic_test.cpp
  232. //
  233. // Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd.
  234. // Copyright (c) 2006 Ion Gaztanaga
  235. //
  236. // Distributed under the Boost Software License, Version 1.0. (See
  237. // accompanying file LICENSE_1_0.txt or copy at
  238. // http://www.boost.org/LICENSE_1_0.txt)
  239. //
  240. static int cnt = 0;
  241. struct X
  242. {
  243. X(){ ++cnt; }
  244. // virtual destructor deliberately omitted
  245. virtual ~X(){ --cnt; }
  246. virtual int id() const
  247. { return 1; }
  248. private:
  249. X(X const &);
  250. X & operator= (X const &);
  251. };
  252. struct Y: public X
  253. {
  254. Y(){ ++cnt; }
  255. virtual ~Y(){ --cnt; }
  256. virtual int id() const
  257. { return 2; }
  258. private:
  259. Y(Y const &);
  260. Y & operator= (Y const &);
  261. };
  262. int * get_object()
  263. { ++cnt; return &cnt; }
  264. void release_object(int * p)
  265. { BOOST_TEST(p == &cnt); --cnt; }
  266. template<class T, class A, class D>
  267. void test_is_X(shared_ptr<T, A, D> const & p)
  268. {
  269. BOOST_TEST(p->id() == 1);
  270. BOOST_TEST((*p).id() == 1);
  271. }
  272. template<class T, class A, class D>
  273. void test_is_X(weak_ptr<T, A, D> const & p)
  274. {
  275. BOOST_TEST(p.get() != 0);
  276. BOOST_TEST(p.get()->id() == 1);
  277. }
  278. template<class T, class A, class D>
  279. void test_is_Y(shared_ptr<T, A, D> const & p)
  280. {
  281. BOOST_TEST(p->id() == 2);
  282. BOOST_TEST((*p).id() == 2);
  283. }
  284. template<class T, class A, class D>
  285. void test_is_Y(weak_ptr<T, A, D> const & p)
  286. {
  287. shared_ptr<T, A, D> q = p.lock();
  288. BOOST_TEST(q.get() != 0);
  289. BOOST_TEST(q->id() == 2);
  290. }
  291. template<class T, class T2>
  292. void test_eq(T const & a, T2 const & b)
  293. {
  294. BOOST_TEST(a == b);
  295. BOOST_TEST(!(a != b));
  296. BOOST_TEST(!(a < b));
  297. BOOST_TEST(!(b < a));
  298. }
  299. template<class T, class T2>
  300. void test_ne(T const & a, T2 const & b)
  301. {
  302. BOOST_TEST(!(a == b));
  303. BOOST_TEST(a != b);
  304. BOOST_TEST(a < b || b < a);
  305. BOOST_TEST(!(a < b && b < a));
  306. }
  307. template<class T, class U, class A, class D, class D2>
  308. void test_shared(weak_ptr<T, A, D> const & a, weak_ptr<U, A, D2> const & b)
  309. {
  310. BOOST_TEST(!(a < b));
  311. BOOST_TEST(!(b < a));
  312. }
  313. template<class T, class U, class A, class D, class D2>
  314. void test_nonshared(weak_ptr<T, A, D> const & a, weak_ptr<U, A, D2> const & b)
  315. {
  316. BOOST_TEST(a < b || b < a);
  317. BOOST_TEST(!(a < b && b < a));
  318. }
  319. template<class T, class U>
  320. void test_eq2(T const & a, U const & b)
  321. {
  322. BOOST_TEST(a == b);
  323. BOOST_TEST(!(a != b));
  324. }
  325. template<class T, class U>
  326. void test_ne2(T const & a, U const & b)
  327. {
  328. BOOST_TEST(!(a == b));
  329. BOOST_TEST(a != b);
  330. }
  331. template<class T, class A, class D>
  332. void test_is_zero(shared_ptr<T, A, D> const & p)
  333. {
  334. BOOST_TEST(!p);
  335. BOOST_TEST(p.get() == 0);
  336. }
  337. template<class T, class A, class D>
  338. void test_is_nonzero(shared_ptr<T, A, D> const & p)
  339. {
  340. // p? true: false is used to test p in a boolean context.
  341. // BOOST_TEST(p) is not guaranteed to test the conversion,
  342. // as the macro might test !!p instead.
  343. BOOST_TEST(p? true: false);
  344. BOOST_TEST(p.get() != 0);
  345. }
  346. int basic_shared_ptr_test()
  347. {
  348. typedef managed_shared_memory::segment_manager segment_mngr_t;
  349. typedef allocator<void, segment_mngr_t> v_allocator_t;
  350. typedef deleter<X, segment_mngr_t> x_deleter_t;
  351. typedef deleter<Y, segment_mngr_t> y_deleter_t;
  352. typedef shared_ptr<X, v_allocator_t, x_deleter_t> x_shared_ptr;
  353. typedef shared_ptr<Y, v_allocator_t, y_deleter_t> y_shared_ptr;
  354. typedef weak_ptr<X, v_allocator_t, x_deleter_t> x_weak_ptr;
  355. typedef weak_ptr<Y, v_allocator_t, y_deleter_t> y_weak_ptr;
  356. std::string process_name;
  357. test::get_process_id_name(process_name);
  358. shared_memory_object::remove(process_name.c_str());
  359. {
  360. managed_shared_memory shmem(create_only, process_name.c_str(), 10000);
  361. {
  362. v_allocator_t v_allocator (shmem.get_segment_manager());
  363. x_deleter_t x_deleter (shmem.get_segment_manager());
  364. y_deleter_t y_deleter (shmem.get_segment_manager());
  365. y_shared_ptr p (shmem.construct<Y>(anonymous_instance)(), v_allocator, y_deleter);
  366. x_shared_ptr p2(shmem.construct<X>(anonymous_instance)(), v_allocator, x_deleter);
  367. test_is_nonzero(p);
  368. test_is_nonzero(p2);
  369. test_is_Y(p);
  370. test_is_X(p2);
  371. test_ne(p, p2);
  372. {
  373. shared_ptr<X, v_allocator_t, y_deleter_t> q(p);
  374. test_eq(p, q);
  375. }
  376. y_shared_ptr p3 (dynamic_pointer_cast<Y>(p));
  377. shared_ptr<Y, v_allocator_t, x_deleter_t> p4 (dynamic_pointer_cast<Y>(p2));
  378. test_is_nonzero(p3);
  379. test_is_zero(p4);
  380. BOOST_TEST(p.use_count() == 2);
  381. BOOST_TEST(p2.use_count() == 1);
  382. BOOST_TEST(p3.use_count() == 2);
  383. test_is_Y(p3);
  384. test_eq2(p, p3);
  385. test_ne2(p2, p4);
  386. shared_ptr<void, v_allocator_t, y_deleter_t> p5(p);
  387. test_is_nonzero(p5);
  388. test_eq2(p, p5);
  389. BOOST_TEST(p5.use_count() == 3);
  390. x_weak_ptr wp1(p2);
  391. BOOST_TEST(!wp1.expired());
  392. BOOST_TEST(wp1.use_count() != 0);
  393. p.reset();
  394. p2.reset();
  395. p3.reset();
  396. p4.reset();
  397. test_is_zero(p);
  398. test_is_zero(p2);
  399. test_is_zero(p3);
  400. test_is_zero(p4);
  401. BOOST_TEST(p5.use_count() == 1);
  402. BOOST_TEST(wp1.expired());
  403. BOOST_TEST(wp1.use_count() == 0);
  404. try{
  405. x_shared_ptr sp1(wp1);
  406. BOOST_ERROR("shared_ptr<X, A, D> sp1(wp1) failed to throw");
  407. }
  408. catch(boost::interprocess::bad_weak_ptr const &)
  409. {}
  410. test_is_zero(wp1.lock());
  411. weak_ptr<X, v_allocator_t, y_deleter_t> wp2 = static_pointer_cast<X>(p5);
  412. BOOST_TEST(wp2.use_count() == 1);
  413. test_is_Y(wp2);
  414. test_nonshared(wp1, wp2);
  415. // Scoped to not affect the subsequent use_count() tests.
  416. {
  417. shared_ptr<X, v_allocator_t, y_deleter_t> sp2(wp2);
  418. test_is_nonzero(wp2.lock());
  419. }
  420. y_weak_ptr wp3 = dynamic_pointer_cast<Y>(wp2.lock());
  421. BOOST_TEST(wp3.use_count() == 1);
  422. test_shared(wp2, wp3);
  423. weak_ptr<X, v_allocator_t, y_deleter_t> wp4(wp3);
  424. BOOST_TEST(wp4.use_count() == 1);
  425. test_shared(wp2, wp4);
  426. wp1 = p2;
  427. test_is_zero(wp1.lock());
  428. wp1 = p4;
  429. x_weak_ptr wp5;
  430. bool b1 = wp1 < wp5;
  431. bool b2 = wp5 < wp1;
  432. y_shared_ptr p6 = static_pointer_cast<Y>(p5);
  433. p5.reset();
  434. p6.reset();
  435. BOOST_TEST(wp1.use_count() == 0);
  436. BOOST_TEST(wp2.use_count() == 0);
  437. BOOST_TEST(wp3.use_count() == 0);
  438. // Test operator< stability for std::set< weak_ptr<> >
  439. // Thanks to Joe Gottman for pointing this out
  440. BOOST_TEST(b1 == (wp1 < wp5));
  441. BOOST_TEST(b2 == (wp5 < wp1));
  442. }
  443. BOOST_TEST(cnt == 0);
  444. }
  445. shared_memory_object::remove(process_name.c_str());
  446. return boost::report_errors();
  447. }
  448. struct alias_tester
  449. {
  450. int v_;
  451. explicit alias_tester( int v ): v_( v )
  452. {
  453. }
  454. ~alias_tester()
  455. {
  456. v_ = 0;
  457. }
  458. };
  459. void test_alias()
  460. {
  461. typedef managed_shared_memory::segment_manager segment_mngr_t;
  462. typedef allocator<void, segment_mngr_t> v_allocator_t;
  463. typedef deleter<int, segment_mngr_t> int_deleter_t;
  464. typedef shared_ptr<int, v_allocator_t, int_deleter_t> int_shared_ptr;
  465. typedef shared_ptr<const int, v_allocator_t, int_deleter_t> const_int_shared_ptr;
  466. std::string process_name;
  467. test::get_process_id_name(process_name);
  468. shared_memory_object::remove(process_name.c_str());
  469. {
  470. managed_shared_memory shmem(create_only, process_name.c_str(), 10000);
  471. {
  472. int m = 0;
  473. int_shared_ptr p;
  474. int_shared_ptr p2( p, &m );
  475. BOOST_TEST( ipcdetail::to_raw_pointer(p2.get()) == &m );
  476. BOOST_TEST( p2? true: false );
  477. BOOST_TEST( !!p2 );
  478. BOOST_TEST( p2.use_count() == p.use_count() );
  479. BOOST_TEST( !( p < p2 ) && !( p2 < p ) );
  480. p2.reset( p, static_cast<int*>(0) );
  481. BOOST_TEST( p2.get() == 0 );
  482. BOOST_TEST( p2? false: true );
  483. BOOST_TEST( !p2 );
  484. BOOST_TEST( p2.use_count() == p.use_count() );
  485. BOOST_TEST( !( p < p2 ) && !( p2 < p ) );
  486. }
  487. {
  488. int m = 0;
  489. int_shared_ptr p(make_managed_shared_ptr
  490. (shmem.construct<int>(anonymous_instance)(), shmem));
  491. const_int_shared_ptr p2( p, &m );
  492. BOOST_TEST( ipcdetail::to_raw_pointer(p2.get()) == &m );
  493. BOOST_TEST( p2? true: false );
  494. BOOST_TEST( !!p2 );
  495. BOOST_TEST( p2.use_count() == p.use_count() );
  496. BOOST_TEST( !( p < p2 ) && !( p2 < p ) );
  497. int_shared_ptr p_nothrow(make_managed_shared_ptr
  498. (shmem.construct<int>(anonymous_instance)(), shmem, std::nothrow));
  499. }
  500. }
  501. shared_memory_object::remove(process_name.c_str());
  502. }
  503. int main()
  504. {
  505. if(0 != simple_test())
  506. return 1;
  507. if(0 != string_shared_ptr_vector_insertion_test())
  508. return 1;
  509. if(0 != basic_shared_ptr_test())
  510. return 1;
  511. test_alias();
  512. }
  513. #include <boost/interprocess/detail/config_end.hpp>