old_if_copyable.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. // Copyright (C) 2008-2018 Lorenzo Caminiti
  2. // Distributed under the Boost Software License, Version 1.0 (see accompanying
  3. // file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
  4. // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html
  5. #include <boost/contract.hpp>
  6. #include <boost/type_traits.hpp>
  7. #include <boost/noncopyable.hpp>
  8. #include <cassert>
  9. //[old_if_copyable_offset
  10. template<typename T> // T might or might not be copyable.
  11. void offset(T& x, int count) {
  12. // No compiler error if T has no copy constructor...
  13. boost::contract::old_ptr_if_copyable<T> old_x = BOOST_CONTRACT_OLDOF(x);
  14. boost::contract::check c = boost::contract::function()
  15. .postcondition([&] {
  16. // ...but old value null if T has no copy constructor.
  17. if(old_x) BOOST_CONTRACT_ASSERT(x == *old_x + count);
  18. })
  19. ;
  20. x += count;
  21. }
  22. //]
  23. //[old_if_copyable_w_decl
  24. // Copyable type but...
  25. class w {
  26. public:
  27. w(w const&) { /* Some very expensive copy operation here... */ }
  28. /* ... */
  29. //]
  30. w() : num_(0) {}
  31. int operator+(int i) const { return num_ + i; }
  32. w& operator+=(int i) { num_ += i; return *this; }
  33. bool operator==(int i) const { return long(num_) == i; }
  34. private:
  35. unsigned long num_;
  36. };
  37. //[old_if_copyable_w_spec
  38. // ...never copy old values for type `w` (because its copy is too expensive).
  39. namespace boost { namespace contract {
  40. template<>
  41. struct is_old_value_copyable<w> : boost::false_type {};
  42. } }
  43. //]
  44. //[old_if_copyable_p_decl
  45. // Non-copyable type but...
  46. class p : private boost::noncopyable {
  47. int* num_;
  48. friend struct boost::contract::old_value_copy<p>;
  49. /* ... */
  50. //]
  51. public:
  52. p() : num_(new int(0)) {}
  53. ~p() { delete num_; }
  54. int operator+(int i) const { return *num_ + i; }
  55. p& operator+=(int i) { *num_ += i; return *this; }
  56. bool operator==(int i) const { return *num_ == i; }
  57. };
  58. //[old_if_copyable_p_spec
  59. // ...still copy old values for type `p` (using a deep copy).
  60. namespace boost { namespace contract {
  61. template<>
  62. struct old_value_copy<p> {
  63. explicit old_value_copy(p const& old) {
  64. *old_.num_ = *old.num_; // Deep copy pointed value.
  65. }
  66. p const& old() const { return old_; }
  67. private:
  68. p old_;
  69. };
  70. template<>
  71. struct is_old_value_copyable<p> : boost::true_type {};
  72. } }
  73. //]
  74. //[old_if_copyable_n_decl
  75. class n { // Do not want to use boost::noncopyable but...
  76. int num_;
  77. private:
  78. n(n const&); // ...unimplemented private copy constructor (so non-copyable).
  79. /* ... */
  80. //]
  81. public:
  82. n() : num_(0) {}
  83. int operator+(int i) const { return num_ + i; }
  84. n& operator+=(int i) { num_ += i; return *this; }
  85. bool operator==(int i) const { return num_ == i; }
  86. };
  87. //[old_if_copyable_n_spec
  88. // Specialize `boost::is_copy_constructible` (no need for this on C++11).
  89. namespace boost { namespace contract {
  90. template<>
  91. struct is_old_value_copyable<n> : boost::false_type {};
  92. } }
  93. //]
  94. int main() {
  95. int i = 0; // Copy constructor, copy and check old values.
  96. offset(i, 3);
  97. assert(i == 3);
  98. w j; // Expensive copy constructor, so never copy or check old values.
  99. offset(j, 3);
  100. assert(j == 3);
  101. p k; // No copy constructor, but still copy and check old values.
  102. offset(k, 3);
  103. assert(k == 3);
  104. n h; // No copy constructor, no compiler error but no old value checks.
  105. offset(h, 3);
  106. assert(h == 3);
  107. return 0;
  108. }