scope_exit.cpp 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. // Copyright (C) 2009-2012 Lorenzo Caminiti
  2. // Distributed under the Boost Software License, Version 1.0
  3. // (see accompanying file LICENSE_1_0.txt or a copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. // Home at http://www.boost.org/libs/local_function
  6. #include "scope_exit.hpp"
  7. #include <boost/foreach.hpp>
  8. #include <boost/typeof/typeof.hpp>
  9. #include <boost/typeof/std/vector.hpp>
  10. #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
  11. #include <boost/detail/lightweight_test.hpp>
  12. #include <vector>
  13. #include <iostream>
  14. #include <sstream>
  15. class person {
  16. friend class world;
  17. public:
  18. typedef unsigned int id_t;
  19. typedef unsigned int evolution_t;
  20. person(void): id_(0), evolution_(0) {}
  21. friend std::ostream& operator<<(std::ostream& o, person const& p) {
  22. return o << "person(" << p.id_ << ", " << p.evolution_ << ")";
  23. }
  24. private:
  25. id_t id_;
  26. evolution_t evolution_;
  27. };
  28. BOOST_TYPEOF_REGISTER_TYPE(person)
  29. class world {
  30. public:
  31. typedef unsigned int id_t;
  32. world(void): next_id_(1) {}
  33. void add_person(person const& a_person);
  34. friend std::ostream& operator<<(std::ostream& o, world const& w) {
  35. o << "world(" << w.next_id_ << ", {";
  36. BOOST_FOREACH(person const& p, w.persons_) {
  37. o << " " << p << ", ";
  38. }
  39. return o << "})";
  40. }
  41. private:
  42. id_t next_id_;
  43. std::vector<person> persons_;
  44. };
  45. BOOST_TYPEOF_REGISTER_TYPE(world)
  46. void world::add_person(person const& a_person) {
  47. persons_.push_back(a_person);
  48. // This block must be no-throw.
  49. //[scope_exit
  50. person& p = persons_.back();
  51. person::evolution_t checkpoint = p.evolution_;
  52. SCOPE_EXIT(const bind checkpoint, const bind& p, bind this_) {
  53. if (checkpoint == p.evolution_) this_->persons_.pop_back();
  54. } SCOPE_EXIT_END
  55. //]
  56. // ...
  57. checkpoint = ++p.evolution_;
  58. // Assign new id to the person.
  59. world::id_t const prev_id = p.id_;
  60. p.id_ = next_id_++;
  61. SCOPE_EXIT(const bind checkpoint, const bind prev_id, bind& p,
  62. bind& next_id_) {
  63. if (checkpoint == p.evolution_) {
  64. next_id_ = p.id_;
  65. p.id_ = prev_id;
  66. }
  67. } SCOPE_EXIT_END
  68. // ...
  69. checkpoint = ++p.evolution_;
  70. }
  71. int main(void) {
  72. person adam, eva;
  73. std::ostringstream oss;
  74. oss << adam;
  75. std::cout << oss.str() << std::endl;
  76. BOOST_TEST(oss.str() == "person(0, 0)");
  77. oss.str("");
  78. oss << eva;
  79. std::cout << oss.str() << std::endl;
  80. BOOST_TEST(oss.str() == "person(0, 0)");
  81. world w;
  82. w.add_person(adam);
  83. w.add_person(eva);
  84. oss.str("");
  85. oss << w;
  86. std::cout << oss.str() << std::endl;
  87. BOOST_TEST(oss.str() == "world(3, { person(1, 2), person(2, 2), })");
  88. return boost::report_errors();
  89. }