├── Chapter04 ├── list_swap.C ├── member_swap.C ├── nonmember_swap_friend.C ├── nonmember_swap_friend_forward.C ├── nonmember_swap_func.C ├── nonmember_swap_none.C ├── nonmember_swap_std.C ├── nonmember_swap_std_only.C ├── std_swap_copyable.C ├── std_swap_movable.C ├── std_swap_noncopyable.C ├── std_swap_nonmovable.C ├── swap_rollback.C ├── vector_empty.C └── vector_swap.C ├── Chapter05 ├── memory1.C ├── mutex1.C ├── scoped_ptr1.C └── scoped_ptr1_bm.C ├── Chapter06 ├── smartptr.C └── smartptr_extra.C ├── Chapter07 ├── fast_sort1.C ├── fast_sort2.C ├── fast_sort3.C ├── fast_sort4.C ├── incomplete_class.C ├── incomplete_ctor.C ├── incomplete_template1.C ├── incomplete_template2.C ├── incomplete_template_ctor.C ├── is_class1.C ├── is_class2.C ├── is_class3.C ├── is_valid1.C ├── is_valid1a.C ├── is_valid2.C ├── is_valid2a.C ├── is_valid3.C ├── is_valid4.C ├── multiply1.C ├── multiply2.C ├── multiply3.C ├── multiply4.C ├── multiply5.C ├── no_sfinae1.C ├── overload1.C ├── overload1a.C ├── overload1b.C ├── overload2.C ├── overload3.C ├── overload4.C ├── overload5.C ├── overload6.C ├── sfinae1.C ├── sfinae1a.C ├── sfinae2.C ├── sfinae3.C └── sfinae4.C ├── Chapter08 ├── function_call.C ├── not_equal.C ├── not_equal_friend.C ├── registry.C └── visitor.C ├── Chapter09 ├── city.C ├── cout_chaining.C ├── named_args.C ├── named_args1.C ├── named_args1_extra.C ├── named_args_extra.C ├── poly_chain1.C ├── poly_chain2.C ├── poly_chain2a.C └── poly_chain3.C ├── Chapter10 ├── malloc1.C ├── malloc2.C ├── malloc3.C ├── smartptr.C ├── string1.C ├── string2.C ├── vector1.C └── vector2.C ├── Chapter11 ├── 01_bad.C ├── 02_trycatch.C ├── 02a_trycatch_cleanup.C ├── 02b_trycatch_raiicleanup.C ├── 03_raii.C ├── 04_scopeguard_basic.C ├── 04a_scopeguard_basic_typedef.C ├── 05_scopeguard_basic_move.C ├── 05a_scopeguard_basic_move_cpp14.C ├── 06_scopeguard_obj.C ├── 07_scopeguard_lambda.C ├── 07a_scopeguard_lambda_cleanup.C ├── 08_scopeguard_exception.C ├── 09_scopeguard_shielded.C ├── 10_scopeguard_lambda_cpp17.C ├── 11_scopeguard_on_exit.C ├── 11a_scopeguard_on_exit_named.C ├── 12_scopeguard_on_fail_cpp17.C ├── 12a_scopeguard_on_fail.C ├── 12b_scopeguard_on_fail_gcc.C ├── 13_scopeguard_te.C └── 13a_scopeguard_te_benchmark.C ├── Chapter12 ├── equal_friend_factory_crtp.C ├── friend_factory.C ├── friend_nontemplate.C ├── friend_template.C ├── plus_friend.C ├── plus_friend1.C ├── plus_friend1_template.C ├── plus_friend_factory.C ├── plus_friend_factory_crtp.C ├── plus_friend_factory_ns.C ├── plus_friend_template.C └── plus_member.C ├── Chapter13 ├── ctor_dtor_dynamic_type.C ├── ctor_dtor_static_type.C ├── ctor_dtor_virtual_type.C ├── poly_copy.C ├── poly_copy_unique.C ├── poly_copy_unique_crtp.C ├── poly_copy_unique_crtp1.C ├── poly_copy_unique_crtp2.C ├── type_registry.C ├── type_registry_unique.C └── unit_factory.C ├── Chapter15 ├── singleton_eager.C ├── singleton_lazy_leaky.C ├── singleton_meyers.C ├── singleton_meyers_pimpl.C ├── singleton_meyers_pimpl1.C ├── singleton_noaccess.C ├── singleton_static.C └── singleton_static1.C ├── Chapter16 ├── 01_scoped_ptr.C ├── 02_scoped_ptr.C ├── 02a_scoped_ptr_bug.C ├── 02b_scoped_ptr.C ├── 02c_scoped_ptr.C ├── 02d_scoped_ptr.C ├── 02e_scoped_ptr.C ├── 02f_scoped_ptr.C ├── 02g_scoped_ptr.C ├── 03_scoped_ptr.C ├── 03a_scoped_ptr.C ├── 03b_scoped_ptr.C ├── 04_scoped_movable_ptr.C ├── 04a_scoped_movable_ptr.C ├── 05_shared_ptr.C ├── 05a_shared_ptr_test.C ├── 05b_shared_ptr_test.C ├── 06_shared_ptr_debug.C ├── 07_shared_ptr_debug.C ├── 07a_shared_ptr_debug.C ├── 08_scoped_ptr_enable_if.C ├── 08a_scoped_ptr_enable_if.C ├── 08b_scoped_ptr_enable_if.C ├── 08c_scoped_ptr_enable_if.C ├── 09_shared_ptr.C ├── 09a_shared_ptr.C ├── 10_shared_ptr_rebind.C └── 11_pack.C ├── Chapter17 ├── 01_decorator.C ├── 01a_decorator.C ├── 02_decorator.C ├── 02a_decorator.C ├── 03_decorator.C ├── 03a_decorator.C ├── 04_decorator.C ├── 04a_decorator.C ├── 04b_decorator.C ├── 04c_decorator.C ├── 04d_decorator.C ├── 05_locking_queue.C ├── 05a_locking_queue.C ├── 06_adapter_curry.C ├── 06a_adapter_curry.C ├── 06b_adapter_lambda.C ├── 06c_adapter_bind.C ├── 06c_adapter_lambda.C ├── 06d_adapter_bind.C ├── 07_template_template_adapter.C ├── 07a_template_template_adapter.C ├── 07b_template_template_adapter.C ├── 07c_template_template_adapter.C ├── 08_time_adapter.C ├── 08a_time_adapter.C └── 09_value_decorators.C ├── Chapter18 ├── 01_visitor.C ├── 01a_visitor.C ├── 01b_visitor.C ├── 02_visitor_args.C ├── 02a_visitor_retval.C ├── 03_container_visitor.C ├── 03a_composite_visitor.C ├── 03b_serialization_visitor.C ├── 03c_serialization_visitor.C ├── 04_visitor_template.C ├── 04a_visitor_template.C ├── 04b_visitor_template.C ├── 04c_visitor_template.C ├── 05_acyclic_visitor.C ├── 05a_acyclic_visitor.C ├── 05b_acyclic_visitor.C ├── 06_static_visitor.C ├── 07_serialize_visitor.C └── 07a_serialize_visitor.C ├── LICENSE └── README.md /Chapter04/list_swap.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef std::list T; 6 | 7 | int main() { 8 | T t1({1, 2, 3, 4}); 9 | T t2({5, 6, 7, 8}); 10 | std::cout << "\nInitial:" << std::endl; 11 | std::cout << "t1:"; for (auto x: t1) std::cout << " " << x; std::cout << std::endl; 12 | std::cout << "t2:"; for (auto x: t2) std::cout << " " << x; std::cout << std::endl; 13 | 14 | t1.swap(t2); 15 | std::cout << "\nAfter member swap:" << std::endl; 16 | std::cout << "t1:"; for (auto x: t1) std::cout << " " << x; std::cout << std::endl; 17 | std::cout << "t2:"; for (auto x: t2) std::cout << " " << x; std::cout << std::endl; 18 | 19 | swap(t1, t2); 20 | std::cout << "\nAfter non-member swap:" << std::endl; 21 | std::cout << "t1:"; for (auto x: t1) std::cout << " " << x; std::cout << std::endl; 22 | std::cout << "t2:"; for (auto x: t2) std::cout << " " << x; std::cout << std::endl; 23 | 24 | std::swap(t1, t2); 25 | std::cout << "\nAfter std::swap:" << std::endl; 26 | std::cout << "t1:"; for (auto x: t1) std::cout << " " << x; std::cout << std::endl; 27 | std::cout << "t2:"; for (auto x: t2) std::cout << " " << x; std::cout << std::endl; 28 | } 29 | -------------------------------------------------------------------------------- /Chapter04/member_swap.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class C { 5 | public: 6 | explicit C(int i) : i_(i) {} 7 | void swap(C& rhs) noexcept { 8 | using std::swap; 9 | swap(i_, rhs.i_); 10 | } 11 | int i_; 12 | }; 13 | 14 | 15 | int main() { 16 | C c1(1), c2(2); 17 | std::cout << "\nInitial:" << std::endl; 18 | std::cout << "c1: " << c1.i_ << " c2: " << c2.i_ << std::endl; 19 | 20 | //std::swap(c1, c2); // Not the best way 21 | c1.swap(c2); 22 | std::cout << "\nAfter swap:" << std::endl; 23 | std::cout << "c1: " << c1.i_ << " c2: " << c2.i_ << std::endl; 24 | } 25 | -------------------------------------------------------------------------------- /Chapter04/nonmember_swap_friend.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using std::swap; 5 | 6 | namespace N { 7 | class C { 8 | public: 9 | explicit C(int i) : i_(i) {} 10 | C(const C& rhs) : i_(rhs.i_) { std::cout << "C(const C&)" << std::endl; } 11 | C& operator=(const C& rhs) { i_ = rhs.i_; std::cout << "C = C&" << std::endl; return *this; } 12 | void swap(C& rhs) noexcept { std::cout << "C::swap(C&)" << std::endl; std::swap(i_, rhs.i_); } 13 | friend void swap(C& lhs, C& rhs) noexcept { std::cout << "friend C::swap" << std::endl; lhs.swap(rhs); } 14 | int i_; 15 | }; 16 | } 17 | 18 | 19 | int main() { 20 | N::C c1(1), c2(2); 21 | std::cout << "\nInitial:" << std::endl; 22 | std::cout << "c1: " << c1.i_ << " c2: " << c2.i_ << std::endl; 23 | 24 | std::swap(c1, c2); 25 | std::cout << "\nAfter swap:" << std::endl; 26 | std::cout << "c1: " << c1.i_ << " c2: " << c2.i_ << std::endl; 27 | 28 | swap(c1, c2); 29 | std::cout << "\nAfter swap:" << std::endl; 30 | std::cout << "c1: " << c1.i_ << " c2: " << c2.i_ << std::endl; 31 | } 32 | -------------------------------------------------------------------------------- /Chapter04/nonmember_swap_friend_forward.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using std::swap; 5 | 6 | namespace N { 7 | class C { 8 | public: 9 | explicit C(int i) : i_(i) {} 10 | C(const C& rhs) : i_(rhs.i_) { std::cout << "C(const C&)" << std::endl; } 11 | C& operator=(const C& rhs) { i_ = rhs.i_; std::cout << "C = C&" << std::endl; return *this; } 12 | void swap(C& rhs) noexcept { std::cout << "C::swap(C&)" << std::endl; std::swap(i_, rhs.i_); } 13 | friend void swap(C& lhs, C& rhs) noexcept; 14 | int i_; 15 | }; 16 | void swap(C& lhs, C& rhs) noexcept { std::cout << "friend C::swap" << std::endl; lhs.swap(rhs); } 17 | } 18 | 19 | 20 | int main() { 21 | N::C c1(1), c2(2); 22 | std::cout << "\nInitial:" << std::endl; 23 | std::cout << "c1: " << c1.i_ << " c2: " << c2.i_ << std::endl; 24 | 25 | std::swap(c1, c2); 26 | std::cout << "\nAfter swap:" << std::endl; 27 | std::cout << "c1: " << c1.i_ << " c2: " << c2.i_ << std::endl; 28 | 29 | swap(c1, c2); 30 | std::cout << "\nAfter swap:" << std::endl; 31 | std::cout << "c1: " << c1.i_ << " c2: " << c2.i_ << std::endl; 32 | } 33 | -------------------------------------------------------------------------------- /Chapter04/nonmember_swap_func.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using std::swap; 5 | 6 | namespace N { 7 | class C { 8 | public: 9 | explicit C(int i) : i_(i) {} 10 | C(const C& rhs) : i_(rhs.i_) { std::cout << "C(const C&)" << std::endl; } 11 | C& operator=(const C& rhs) { i_ = rhs.i_; std::cout << "C = C&" << std::endl; return *this; } 12 | void swap(C& rhs) noexcept { std::cout << "C::swap(C&)" << std::endl; std::swap(i_, rhs.i_); } 13 | int i_; 14 | }; 15 | void swap(C& lhs, C& rhs) noexcept { std::cout << "::swap(C&, C&)" << std::endl; lhs.swap(rhs); } 16 | } 17 | 18 | 19 | int main() { 20 | N::C c1(1), c2(2); 21 | std::cout << "\nInitial:" << std::endl; 22 | std::cout << "c1: " << c1.i_ << " c2: " << c2.i_ << std::endl; 23 | 24 | std::swap(c1, c2); 25 | std::cout << "\nAfter swap:" << std::endl; 26 | std::cout << "c1: " << c1.i_ << " c2: " << c2.i_ << std::endl; 27 | 28 | swap(c1, c2); 29 | std::cout << "\nAfter swap:" << std::endl; 30 | std::cout << "c1: " << c1.i_ << " c2: " << c2.i_ << std::endl; 31 | } 32 | -------------------------------------------------------------------------------- /Chapter04/nonmember_swap_none.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using std::swap; 5 | 6 | namespace N { 7 | class C { 8 | public: 9 | explicit C(int i) : i_(i) {} 10 | C(const C& rhs) : i_(rhs.i_) { std::cout << "C(const C&)" << std::endl; } 11 | C& operator=(const C& rhs) { i_ = rhs.i_; std::cout << "C = C&" << std::endl; return *this; } 12 | void swap(C& rhs) noexcept { std::cout << "C::swap" << std::endl; std::swap(i_, rhs.i_); } 13 | int i_; 14 | }; 15 | } 16 | 17 | 18 | int main() { 19 | N::C c1(1), c2(2); 20 | std::cout << "\nInitial:" << std::endl; 21 | std::cout << "c1: " << c1.i_ << " c2: " << c2.i_ << std::endl; 22 | 23 | std::swap(c1, c2); 24 | std::cout << "\nAfter swap:" << std::endl; 25 | std::cout << "c1: " << c1.i_ << " c2: " << c2.i_ << std::endl; 26 | 27 | swap(c1, c2); 28 | std::cout << "\nAfter swap:" << std::endl; 29 | std::cout << "c1: " << c1.i_ << " c2: " << c2.i_ << std::endl; 30 | } 31 | -------------------------------------------------------------------------------- /Chapter04/nonmember_swap_std.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using std::swap; 5 | 6 | namespace N { 7 | class C { 8 | public: 9 | explicit C(int i) : i_(i) {} 10 | C(const C& rhs) : i_(rhs.i_) { std::cout << "C(const C&)" << std::endl; } 11 | C& operator=(const C& rhs) { i_ = rhs.i_; std::cout << "C = C&" << std::endl; return *this; } 12 | void swap(C& rhs) noexcept { std::cout << "C::swap(C&)" << std::endl; std::swap(i_, rhs.i_); } 13 | int i_; 14 | }; 15 | void swap(C& lhs, C& rhs) noexcept { std::cout << "::swap(C&, C&)" << std::endl; lhs.swap(rhs); } 16 | } 17 | namespace std { 18 | void swap(N::C& lhs, N::C& rhs) noexcept { std::cout << "std::swap(C&, C&)" << std::endl; lhs.swap(rhs); } 19 | } 20 | 21 | 22 | int main() { 23 | N::C c1(1), c2(2); 24 | std::cout << "\nInitial:" << std::endl; 25 | std::cout << "c1: " << c1.i_ << " c2: " << c2.i_ << std::endl; 26 | 27 | std::swap(c1, c2); 28 | std::cout << "\nAfter swap:" << std::endl; 29 | std::cout << "c1: " << c1.i_ << " c2: " << c2.i_ << std::endl; 30 | 31 | swap(c1, c2); 32 | std::cout << "\nAfter swap:" << std::endl; 33 | std::cout << "c1: " << c1.i_ << " c2: " << c2.i_ << std::endl; 34 | } 35 | -------------------------------------------------------------------------------- /Chapter04/nonmember_swap_std_only.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using std::swap; 5 | 6 | namespace N { 7 | class C { 8 | public: 9 | explicit C(int i) : i_(i) {} 10 | C(const C& rhs) : i_(rhs.i_) { std::cout << "C(const C&)" << std::endl; } 11 | C& operator=(const C& rhs) { i_ = rhs.i_; std::cout << "C = C&" << std::endl; return *this; } 12 | void swap(C& rhs) noexcept { std::cout << "C::swap(C&)" << std::endl; std::swap(i_, rhs.i_); } 13 | int i_; 14 | }; 15 | } 16 | namespace std { 17 | void swap(N::C& lhs, N::C& rhs) noexcept { std::cout << "std::swap(C&, C&)" << std::endl; lhs.swap(rhs); } 18 | } 19 | 20 | 21 | int main() { 22 | N::C c1(1), c2(2); 23 | std::cout << "\nInitial:" << std::endl; 24 | std::cout << "c1: " << c1.i_ << " c2: " << c2.i_ << std::endl; 25 | 26 | std::swap(c1, c2); 27 | std::cout << "\nAfter swap:" << std::endl; 28 | std::cout << "c1: " << c1.i_ << " c2: " << c2.i_ << std::endl; 29 | 30 | swap(c1, c2); 31 | std::cout << "\nAfter swap:" << std::endl; 32 | std::cout << "c1: " << c1.i_ << " c2: " << c2.i_ << std::endl; 33 | } 34 | -------------------------------------------------------------------------------- /Chapter04/std_swap_copyable.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class A { 5 | public: 6 | explicit A(int i) : i_(i) {} 7 | A(const A& rhs) : i_(rhs.i_) { std::cout << "A(const A&)" << std::endl; } 8 | A& operator=(const A& rhs) { i_ = rhs.i_; std::cout << "A = A&" << std::endl; return *this; } 9 | int i_; 10 | }; 11 | 12 | 13 | int main() { 14 | A a1(1), a2(2); 15 | std::cout << "\nInitial:" << std::endl; 16 | std::cout << "a1: " << a1.i_ << " a2: " << a2.i_ << std::endl; 17 | 18 | std::swap(a1, a2); // Not the best way 19 | std::cout << "\nAfter swap:" << std::endl; 20 | std::cout << "a1: " << a1.i_ << " a2: " << a2.i_ << std::endl; 21 | } 22 | -------------------------------------------------------------------------------- /Chapter04/std_swap_movable.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class A { 5 | public: 6 | explicit A(int i) : i_(i) {} 7 | A(const A& rhs) : i_(rhs.i_) { std::cout << "A(const A&)" << std::endl; } 8 | A(const A&& rhs) : i_(rhs.i_) { std::cout << "A(const A&&)" << std::endl; } 9 | A& operator=(const A& rhs) { i_ = rhs.i_; std::cout << "A = A&" << std::endl; return *this; } 10 | A& operator=(const A&& rhs) { i_ = rhs.i_; std::cout << "A = A&&" << std::endl; return *this; } 11 | int i_; 12 | }; 13 | 14 | 15 | int main() { 16 | A a1(1), a2(2); 17 | std::cout << "\nInitial:" << std::endl; 18 | std::cout << "a1: " << a1.i_ << " a2: " << a2.i_ << std::endl; 19 | 20 | std::swap(a1, a2); // Not the best way 21 | std::cout << "\nAfter swap:" << std::endl; 22 | std::cout << "a1: " << a1.i_ << " a2: " << a2.i_ << std::endl; 23 | } 24 | -------------------------------------------------------------------------------- /Chapter04/std_swap_noncopyable.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class A { 5 | public: 6 | explicit A(int i) : i_(i) {} 7 | A(const A& rhs) = delete; 8 | A& operator=(const A& rhs) = delete; 9 | int i_; 10 | }; 11 | 12 | 13 | int main() { 14 | A a1(1), a2(2); 15 | std::cout << "\nInitial:" << std::endl; 16 | std::cout << "a1: " << a1.i_ << " a2: " << a2.i_ << std::endl; 17 | 18 | std::swap(a1, a2); // Not the best way 19 | std::cout << "\nAfter swap:" << std::endl; 20 | std::cout << "a1: " << a1.i_ << " a2: " << a2.i_ << std::endl; 21 | } 22 | -------------------------------------------------------------------------------- /Chapter04/std_swap_nonmovable.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class A { 5 | public: 6 | explicit A(int i) : i_(i) {} 7 | A(const A& rhs) : i_(rhs.i_) { std::cout << "A(const A&)" << std::endl; } 8 | A(const A&& rhs) = delete; 9 | A& operator=(const A& rhs) { i_ = rhs.i_; std::cout << "A = A&" << std::endl; return *this; } 10 | A& operator=(const A&& rhs) = delete; 11 | int i_; 12 | }; 13 | 14 | 15 | int main() { 16 | A a1(1), a2(2); 17 | std::cout << "\nInitial:" << std::endl; 18 | std::cout << "a1: " << a1.i_ << " a2: " << a2.i_ << std::endl; 19 | 20 | std::swap(a1, a2); // Not the best way 21 | std::cout << "\nAfter swap:" << std::endl; 22 | std::cout << "a1: " << a1.i_ << " a2: " << a2.i_ << std::endl; 23 | } 24 | -------------------------------------------------------------------------------- /Chapter04/swap_rollback.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int bad_i = -1; 6 | 7 | class C { 8 | public: 9 | explicit C() : i_() {} 10 | explicit C(int i) : i_(i) {} 11 | C(const C& rhs) : i_(rhs.i_) { if (i_ == bad_i) throw i_; } 12 | int i_; 13 | }; 14 | 15 | 16 | typedef std::vector vec; 17 | 18 | C transmogrify(C x) { return C(2*x.i_); } 19 | 20 | void transmogrify_not_safe(const vec& in, vec& out) { 21 | out.resize(0); 22 | out.reserve(in.size()); 23 | for (const auto& x : in) { 24 | out.push_back(transmogrify(x)); 25 | } 26 | } 27 | 28 | void transmogrify_safe(const vec& in, vec& out) { 29 | vec tmp; tmp.reserve(in.size()); 30 | for (const auto& x : in) { 31 | tmp.push_back(transmogrify(x)); 32 | } 33 | out.swap(tmp); 34 | } 35 | 36 | int main() { 37 | vec v1{C(1), C(2), C(3), C(4)}; 38 | { // No exceptions - OK 39 | bad_i = -1; 40 | vec v2; 41 | transmogrify_not_safe(v1, v2); 42 | std::cout << "v2(" << v2.size() << "/" << v2.capacity() << "):"; for (auto x: v2) std::cout << " " << x.i_; std::cout << std::endl; 43 | } 44 | { // exception - partially constructed result 45 | bad_i = 6; 46 | vec v2; 47 | try { transmogrify_not_safe(v1, v2); } catch (...) {} 48 | std::cout << "v2(" << v2.size() << "/" << v2.capacity() << "):"; for (auto x: v2) std::cout << " " << x.i_; std::cout << std::endl; 49 | } 50 | { // exception - initial content lost 51 | bad_i = 1; 52 | vec v2{C(5)}; 53 | try { transmogrify_not_safe(v1, v2); } catch (...) {} 54 | std::cout << "v2(" << v2.size() << "/" << v2.capacity() << "):"; for (auto x: v2) std::cout << " " << x.i_; std::cout << std::endl; 55 | } 56 | { // No exceptions - OK 57 | bad_i = -1; 58 | vec v2; 59 | transmogrify_safe(v1, v2); 60 | std::cout << "v2(" << v2.size() << "/" << v2.capacity() << "):"; for (auto x: v2) std::cout << " " << x.i_; std::cout << std::endl; 61 | } 62 | { // exceptions - rollback 63 | bad_i = 6; 64 | vec v2; 65 | try { transmogrify_safe(v1, v2); } catch (...) {} 66 | std::cout << "v2(" << v2.size() << "/" << v2.capacity() << "):"; for (auto x: v2) std::cout << " " << x.i_; std::cout << std::endl; 67 | } 68 | { // exception - initial content remains 69 | bad_i = 1; 70 | vec v2{C(5)}; 71 | try { transmogrify_safe(v1, v2); } catch (...) {} 72 | std::cout << "v2(" << v2.size() << "/" << v2.capacity() << "):"; for (auto x: v2) std::cout << " " << x.i_; std::cout << std::endl; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Chapter04/vector_empty.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef std::vector V; 6 | 7 | int main() { 8 | { // OK, member swap 9 | V v({1, 2, 3, 4}); 10 | std::cout << "Initial v:"; for (auto x: v) std::cout << " " << x; std::cout << std::endl; 11 | V t; 12 | v.swap(t); 13 | std::cout << "Final v:"; for (auto x: v) std::cout << " " << x; std::cout << std::endl; 14 | } 15 | 16 | #if 0 17 | { // Does not compile, swap() needs an rvalue 18 | V v({1, 2, 3, 4}); 19 | std::cout << "Initial v:"; for (auto x: v) std::cout << " " << x; std::cout << std::endl; 20 | v.swap(V()); 21 | std::cout << "Final v:"; for (auto x: v) std::cout << " " << x; std::cout << std::endl; 22 | } 23 | #endif 24 | 25 | { // Compiles fine, member function call on a temporary 26 | V v({1, 2, 3, 4}); 27 | std::cout << "Initial v:"; for (auto x: v) std::cout << " " << x; std::cout << std::endl; 28 | V().swap(v); 29 | std::cout << "Final v:"; for (auto x: v) std::cout << " " << x; std::cout << std::endl; 30 | } 31 | 32 | { // OK, non-member swap 33 | V v({1, 2, 3, 4}); 34 | std::cout << "Initial v:"; for (auto x: v) std::cout << " " << x; std::cout << std::endl; 35 | V t; 36 | swap(v, t); 37 | std::cout << "Final v:"; for (auto x: v) std::cout << " " << x; std::cout << std::endl; 38 | } 39 | 40 | #if 0 41 | { // Does not compile, swap() needs an rvalue 42 | V v({1, 2, 3, 4}); 43 | std::cout << "Initial v:"; for (auto x: v) std::cout << " " << x; std::cout << std::endl; 44 | swap(v, V()); 45 | std::cout << "Final v:"; for (auto x: v) std::cout << " " << x; std::cout << std::endl; 46 | } 47 | #endif // 0 48 | } 49 | -------------------------------------------------------------------------------- /Chapter04/vector_swap.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef std::vector T; 6 | 7 | int main() { 8 | T t1({1, 2, 3, 4}); 9 | T t2({5, 6, 7, 8}); 10 | std::cout << "\nInitial:" << std::endl; 11 | std::cout << "t1:"; for (auto x: t1) std::cout << " " << x; std::cout << std::endl; 12 | std::cout << "t2:"; for (auto x: t2) std::cout << " " << x; std::cout << std::endl; 13 | 14 | t1.swap(t2); 15 | std::cout << "\nAfter member swap:" << std::endl; 16 | std::cout << "t1:"; for (auto x: t1) std::cout << " " << x; std::cout << std::endl; 17 | std::cout << "t2:"; for (auto x: t2) std::cout << " " << x; std::cout << std::endl; 18 | 19 | swap(t1, t2); 20 | std::cout << "\nAfter non-member swap:" << std::endl; 21 | std::cout << "t1:"; for (auto x: t1) std::cout << " " << x; std::cout << std::endl; 22 | std::cout << "t2:"; for (auto x: t2) std::cout << " " << x; std::cout << std::endl; 23 | 24 | std::swap(t1, t2); 25 | std::cout << "\nAfter std::swap:" << std::endl; 26 | std::cout << "t1:"; for (auto x: t1) std::cout << " " << x; std::cout << std::endl; 27 | std::cout << "t2:"; for (auto x: t2) std::cout << " " << x; std::cout << std::endl; 28 | } 29 | -------------------------------------------------------------------------------- /Chapter05/memory1.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "gtest/gtest.h" 4 | 5 | struct object_counter { 6 | static int count; 7 | static int all_count; 8 | object_counter() { ++count; ++all_count; } 9 | ~object_counter() { --count; } 10 | }; 11 | int object_counter::count = 0; 12 | int object_counter::all_count = 0; 13 | 14 | TEST(Memory, AcquireRelease) { 15 | object_counter::all_count = object_counter::count = 0; 16 | object_counter* p = new object_counter; 17 | EXPECT_EQ(1, object_counter::count); 18 | EXPECT_EQ(1, object_counter::all_count); 19 | delete p; 20 | EXPECT_EQ(0, object_counter::count); 21 | EXPECT_EQ(1, object_counter::all_count); 22 | } 23 | 24 | TEST(Memory, Leak1) { 25 | object_counter::all_count = object_counter::count = 0; 26 | object_counter* p = new object_counter; 27 | EXPECT_EQ(1, object_counter::count); 28 | EXPECT_EQ(1, object_counter::all_count); 29 | (void)p; 30 | //delete p; 31 | EXPECT_EQ(0, object_counter::count); 32 | EXPECT_EQ(1, object_counter::all_count); 33 | } 34 | 35 | TEST(Memory, Leak2) { 36 | object_counter::all_count = object_counter::count = 0; 37 | do { // One-time scope for early exit 38 | object_counter* p = new object_counter; 39 | break; // Early exit 40 | delete p; 41 | } while (false); 42 | EXPECT_EQ(0, object_counter::count); 43 | EXPECT_EQ(1, object_counter::all_count); 44 | } 45 | 46 | struct my_exception { 47 | }; 48 | 49 | TEST(Memory, Leak3) { 50 | object_counter::all_count = object_counter::count = 0; 51 | try { 52 | object_counter* p = new object_counter; 53 | throw my_exception(); 54 | delete p; 55 | } catch ( my_exception& e ) { 56 | } 57 | EXPECT_EQ(0, object_counter::count); 58 | EXPECT_EQ(1, object_counter::all_count); 59 | } 60 | -------------------------------------------------------------------------------- /Chapter05/mutex1.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "gtest/gtest.h" 6 | 7 | class mutex_guard { 8 | public: 9 | explicit mutex_guard(std::mutex& m) : m_(m), must_unlock_(true) { m_.lock(); } 10 | ~mutex_guard() { if (must_unlock_) m_.unlock(); } 11 | void reset() { m_.unlock(); must_unlock_ = false; } 12 | private: 13 | std::mutex& m_; 14 | bool must_unlock_; 15 | }; 16 | 17 | 18 | std::mutex m; 19 | 20 | TEST(mutex_guard, LockUnlock) { 21 | { 22 | mutex_guard lg(m); 23 | EXPECT_FALSE(m.try_lock()); 24 | } 25 | EXPECT_TRUE(m.try_lock()); m.unlock(); 26 | } 27 | 28 | TEST(Scoped_ptr, ThrowNoLeak) { 29 | try { 30 | mutex_guard lg(m); 31 | EXPECT_FALSE(m.try_lock()); 32 | throw 1; 33 | } catch ( ... ) { 34 | } 35 | EXPECT_TRUE(m.try_lock()); m.unlock(); 36 | } 37 | 38 | TEST(mutex_guard, Reset) { 39 | { 40 | mutex_guard lg(m); 41 | EXPECT_FALSE(m.try_lock()); 42 | lg.reset(); 43 | EXPECT_TRUE(m.try_lock()); m.unlock(); 44 | } 45 | EXPECT_TRUE(m.try_lock()); m.unlock(); 46 | } 47 | 48 | -------------------------------------------------------------------------------- /Chapter05/scoped_ptr1_bm.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "benchmark/benchmark.h" 6 | 7 | #define REPEAT2(x) x x 8 | #define REPEAT4(x) REPEAT2(x) REPEAT2(x) 9 | #define REPEAT8(x) REPEAT4(x) REPEAT4(x) 10 | #define REPEAT16(x) REPEAT8(x) REPEAT8(x) 11 | #define REPEAT32(x) REPEAT16(x) REPEAT16(x) 12 | #define REPEAT(x) REPEAT32(x) 13 | 14 | template 15 | class scoped_ptr { 16 | public: 17 | explicit scoped_ptr(T* p) : p_(p) {} 18 | ~scoped_ptr() { delete p_; } 19 | T* operator->() { return p_; } 20 | const T* operator->() const { return p_; } 21 | T& operator*() { return *p_; } 22 | const T& operator*() const { return *p_; } 23 | private: 24 | T* p_; 25 | }; 26 | 27 | void BM_rawptr_construct(benchmark::State& state) { 28 | for (auto _ : state) { 29 | int* p = new int; 30 | delete p; 31 | } 32 | state.SetItemsProcessed(state.iterations()); 33 | } 34 | 35 | void BM_rawptr_dereference(benchmark::State& state) { 36 | int* p = new int; 37 | for (auto _ : state) { 38 | REPEAT(benchmark::DoNotOptimize(*p);) 39 | } 40 | delete p; 41 | state.SetItemsProcessed(32*state.iterations()); 42 | } 43 | 44 | void BM_scoped_ptr_construct(benchmark::State& state) { 45 | for (auto _ : state) { 46 | scoped_ptr p(new int); 47 | } 48 | state.SetItemsProcessed(state.iterations()); 49 | } 50 | 51 | void BM_scoped_ptr_dereference(benchmark::State& state) { 52 | scoped_ptr p(new int); 53 | for (auto _ : state) { 54 | REPEAT(benchmark::DoNotOptimize(*p);) 55 | } 56 | state.SetItemsProcessed(32*state.iterations()); 57 | } 58 | 59 | void BM_unique_ptr_construct(benchmark::State& state) { 60 | for (auto _ : state) { 61 | std::unique_ptr p(new int); 62 | } 63 | state.SetItemsProcessed(state.iterations()); 64 | } 65 | 66 | void BM_unique_ptr_dereference(benchmark::State& state) { 67 | std::unique_ptr p(new int); 68 | for (auto _ : state) { 69 | REPEAT(benchmark::DoNotOptimize(*p);) 70 | } 71 | state.SetItemsProcessed(32*state.iterations()); 72 | } 73 | 74 | BENCHMARK(BM_rawptr_construct); 75 | BENCHMARK(BM_scoped_ptr_construct); 76 | BENCHMARK(BM_unique_ptr_construct); 77 | BENCHMARK(BM_rawptr_dereference); 78 | BENCHMARK(BM_scoped_ptr_dereference); 79 | BENCHMARK(BM_unique_ptr_dereference); 80 | 81 | BENCHMARK_MAIN(); 82 | 83 | -------------------------------------------------------------------------------- /Chapter06/smartptr_extra.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct deleter { 5 | template void operator()(T* p) { delete p; } 6 | }; 7 | 8 | 9 | deleter d; 10 | 11 | std::shared_ptr get_shared_ptr() { 12 | return std::shared_ptr(new int, d); 13 | } 14 | template 15 | struct deleter1 { 16 | void operator()(T* p) { delete p; } 17 | }; 18 | 19 | template 20 | class smartptr_te { 21 | struct deleter_base { 22 | virtual void apply(void*) = 0; 23 | virtual ~deleter_base() {} 24 | }; 25 | template struct deleter : public deleter_base { 26 | deleter(Deleter d) : d_(d) {} 27 | virtual void apply(void* p) { d_(static_cast(p)); } 28 | Deleter d_; 29 | }; 30 | public: 31 | template smartptr_te(T* p, Deleter d) : p_(p), d_(new deleter(d)) {} 32 | ~smartptr_te() { d_->apply(p_); delete d_; } 33 | T* operator->() { return p_; } 34 | const T* operator->() const { return p_; } 35 | private: 36 | T* p_; 37 | deleter_base* d_; 38 | }; 39 | 40 | template 41 | class smartptr_te_lb { 42 | struct deleter_base { 43 | virtual void apply(void*) = 0; 44 | virtual ~deleter_base() {} 45 | }; 46 | template struct deleter : public deleter_base { 47 | deleter(Deleter d) : d_(d) {} 48 | virtual void apply(void* p) { d_(static_cast(p)); } 49 | Deleter d_; 50 | }; 51 | public: 52 | template smartptr_te_lb(T* p, Deleter d) : 53 | p_(p), 54 | d_(sizeof(Deleter) > sizeof(buf_) ? new deleter(d) : new (buf_) deleter(d)) 55 | {} 56 | ~smartptr_te_lb() { 57 | d_->apply(p_); 58 | if (static_cast(d_) == static_cast(buf_)) { 59 | d_->~deleter_base(); 60 | } else { 61 | delete d_; 62 | } 63 | } 64 | T* operator->() { return p_; } 65 | const T* operator->() const { return p_; } 66 | private: 67 | T* p_; 68 | deleter_base* d_; 69 | char buf_[16]; 70 | }; 71 | 72 | smartptr_te get_smartptr_te() { 73 | return smartptr_te(new int, d); 74 | } 75 | 76 | smartptr_te_lb get_smartptr_te_lb() { 77 | return smartptr_te_lb(new int, d); 78 | } 79 | -------------------------------------------------------------------------------- /Chapter07/fast_sort1.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct have_sort { char c; }; 5 | struct have_range { char c; have_sort c1; }; 6 | struct have_nothing { char c; have_range c1; }; 7 | static_assert(sizeof(have_sort) != sizeof(have_nothing), "Do something else for yes/no types"); 8 | template have_sort test_sort(decltype(&T::sort), decltype(&T::sort)); 9 | template have_range test_sort(decltype(&T::begin), decltype(&T::end)); 10 | template have_nothing test_sort(...); 11 | template struct fast_sort_helper; 12 | 13 | template 14 | struct fast_sort_helper { 15 | static void fast_sort(T& x) { 16 | std::cout << "Sorting with T::sort" << std::endl; 17 | x.sort(); 18 | } 19 | }; 20 | 21 | template 22 | struct fast_sort_helper { 23 | static void fast_sort(T& x) { 24 | std::cout << "Sorting with std::sort" << std::endl; 25 | std::sort(x.begin(), x.end()); 26 | } 27 | }; 28 | 29 | template 30 | struct fast_sort_helper { 31 | static void fast_sort(T& x) { 32 | std::cout << "No sort available" << std::endl; 33 | //static_assert(false, "No sort available"); 34 | //static_assert(sizeof(T) < 0, "No sort available"); 35 | } 36 | }; 37 | 38 | template 39 | void fast_sort(T& x) { 40 | fast_sort_helper(NULL, NULL))>::fast_sort(x); 41 | } 42 | 43 | class A { 44 | public: 45 | void sort() {} 46 | }; 47 | 48 | class B { 49 | public: 50 | int* begin() { return i; } 51 | int* end() { return i + 10; } 52 | int i[10]; 53 | }; 54 | 55 | class C { 56 | public: 57 | void f() {} 58 | }; 59 | 60 | int main() { 61 | A a; fast_sort(a); 62 | B b; fast_sort(b); 63 | C c; fast_sort(c); 64 | } 65 | -------------------------------------------------------------------------------- /Chapter07/fast_sort2.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct have_sort { char c; }; 5 | struct have_range { char c; have_sort c1; }; 6 | struct have_nothing { char c; have_range c1; }; 7 | template have_sort test_sort(decltype(&T::sort), decltype(&T::sort)); 8 | template have_range test_sort(decltype(&T::begin), decltype(&T::end)); 9 | template have_nothing test_sort(...); 10 | 11 | template 12 | typename std::enable_if(NULL, NULL)) == sizeof(have_sort)>::type fast_sort(T& x) { 13 | std::cout << "Sorting with T::sort" << std::endl; 14 | x.sort(); 15 | } 16 | template 17 | typename std::enable_if(NULL, NULL)) == sizeof(have_range)>::type fast_sort(T& x) { 18 | std::cout << "Sorting with std::sort" << std::endl; 19 | std::sort(x.begin(), x.end()); 20 | } 21 | template 22 | typename std::enable_if(NULL, NULL)) == sizeof(have_nothing)>::type fast_sort(T& x) { 23 | std::cout << "No sort available" << std::endl; 24 | } 25 | 26 | class A { 27 | public: 28 | void sort() {} 29 | }; 30 | 31 | class B { 32 | public: 33 | int* begin() { return i; } 34 | int* end() { return i + 10; } 35 | int i[10]; 36 | }; 37 | 38 | class C { 39 | public: 40 | void f() {} 41 | }; 42 | 43 | int main() { 44 | A a; fast_sort(a); 45 | B b; fast_sort(b); 46 | C c; fast_sort(c); 47 | } 48 | -------------------------------------------------------------------------------- /Chapter07/fast_sort3.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | struct yes { char c; }; 7 | struct no { char c; yes c1; }; 8 | template yes test_have_sort(decltype(&T::sort)); 9 | template no test_have_sort(...); 10 | template yes test_have_range(decltype(&T::begin), decltype(&T::end)); 11 | template no test_have_range(...); 12 | 13 | template struct fast_sort_helper; 14 | 15 | template 16 | struct fast_sort_helper { 17 | static void fast_sort(T& x) { 18 | std::cout << "Sorting with T::sort, ignoring std::sort" << std::endl; 19 | x.sort(); 20 | } 21 | }; 22 | 23 | template 24 | struct fast_sort_helper { 25 | static void fast_sort(T& x) { 26 | std::cout << "Sorting with T::sort" << std::endl; 27 | x.sort(); 28 | } 29 | }; 30 | 31 | template 32 | struct fast_sort_helper { 33 | static void fast_sort(T& x) { 34 | std::cout << "Sorting with std::sort" << std::endl; 35 | std::sort(x.begin(), x.end()); 36 | } 37 | }; 38 | 39 | template 40 | struct fast_sort_helper { 41 | static void fast_sort(T& x) { 42 | std::cout << "No sort available" << std::endl; 43 | } 44 | }; 45 | 46 | template 47 | void fast_sort(T& x) { 48 | fast_sort_helper(NULL)) == sizeof(yes), sizeof(test_have_range(NULL, NULL)) == sizeof(yes)>::fast_sort(x); 49 | } 50 | 51 | class A { 52 | public: 53 | void sort() {} 54 | }; 55 | 56 | class B { 57 | public: 58 | int* begin() { return i; } 59 | int* end() { return i + 10; } 60 | int i[10]; 61 | }; 62 | 63 | class AB { 64 | public: 65 | void sort() {} 66 | int* begin() { return i; } 67 | int* end() { return i + 10; } 68 | int i[10]; 69 | }; 70 | 71 | class C { 72 | public: 73 | void f() {} 74 | }; 75 | 76 | int main() { 77 | A a; fast_sort(a); 78 | B b; fast_sort(b); 79 | C c; fast_sort(c); 80 | AB ab; fast_sort(ab); 81 | std::vector v; fast_sort(v); 82 | std::list l; fast_sort(l); 83 | } 84 | -------------------------------------------------------------------------------- /Chapter07/incomplete_class.C: -------------------------------------------------------------------------------- 1 | class Base { 2 | public: 3 | Base() : i_() {} 4 | virtual void increment(long v) { i_ += v; } 5 | private: 6 | long i_; 7 | }; 8 | 9 | class Derived : public Base { 10 | public: 11 | Derived() : Base(), j_() {} 12 | void increment(long v) { j_ += v; Base::increment(v); } 13 | // This does not compile even though multiply() is not used: 14 | // Derived is not a template 15 | void multiply(long v) { j_ *= v; Base::multiply(v); } 16 | private: 17 | long j_; 18 | }; 19 | 20 | int main() { 21 | Derived d; 22 | d.increment(5); 23 | } 24 | -------------------------------------------------------------------------------- /Chapter07/incomplete_ctor.C: -------------------------------------------------------------------------------- 1 | class Base { 2 | public: 3 | Base() : i_() {} 4 | virtual void increment(long v) { i_ += v; } 5 | private: 6 | long i_; 7 | }; 8 | 9 | class Derived : public Base { 10 | public: 11 | Derived() : Base(), j_() {} 12 | // This does not compile even though it's not used: 13 | // Derived is not a template 14 | Derived(long i, long j) : Base(i), j_(j) {} 15 | void increment(long v) { j_ += v; Base::increment(v); } 16 | private: 17 | long j_; 18 | }; 19 | 20 | int main() { 21 | Derived d; 22 | d.increment(5); 23 | } 24 | -------------------------------------------------------------------------------- /Chapter07/incomplete_template1.C: -------------------------------------------------------------------------------- 1 | class Base { 2 | public: 3 | Base() : i_() {} 4 | virtual void increment(long v) { i_ += v; } 5 | private: 6 | long i_; 7 | }; 8 | 9 | template 10 | class Derived : public T { 11 | public: 12 | Derived() : T(), j_() {} 13 | void increment(long v) { j_ += v; T::increment(v); } 14 | // This will not compile if we try to call it but is OK by itself. 15 | void multiply(long v) { j_ *= v; T::multiply(v); } 16 | private: 17 | long j_; 18 | }; 19 | 20 | int main() { 21 | Derived d; 22 | d.increment(5); 23 | } 24 | -------------------------------------------------------------------------------- /Chapter07/incomplete_template2.C: -------------------------------------------------------------------------------- 1 | class Base { 2 | public: 3 | Base() : i_() {} 4 | virtual void increment(long v) { i_ += v; } 5 | private: 6 | long i_; 7 | }; 8 | 9 | template 10 | class Derived : public Base { 11 | public: 12 | Derived() : Base(), j_() {} 13 | void increment(long v) { j_ += v; Base::increment(v); } 14 | // This does not compile even though multiply() is not used: 15 | // Base does not depend on the template parameter T 16 | void multiply(long v) { j_ *= v; Base::multiply(v); } 17 | private: 18 | T j_; 19 | }; 20 | 21 | int main() { 22 | Derived d; 23 | d.increment(5); 24 | } 25 | -------------------------------------------------------------------------------- /Chapter07/incomplete_template_ctor.C: -------------------------------------------------------------------------------- 1 | class Base { 2 | public: 3 | Base() : i_() {} 4 | virtual void increment(long v) { i_ += v; } 5 | private: 6 | long i_; 7 | }; 8 | 9 | template 10 | class Derived : public T { 11 | public: 12 | Derived() : T(), j_() {} 13 | Derived(long i, long j) : T(i), j_(j) {} 14 | void increment(long v) { j_ += v; T::increment(v); } 15 | private: 16 | long j_; 17 | }; 18 | 19 | int main() { 20 | Derived d; 21 | d.increment(5); 22 | } 23 | -------------------------------------------------------------------------------- /Chapter07/is_class1.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template void f(int T::*) { std::cout << "T is a class" << std::endl; } 4 | template void f(...) { std::cout << "T is not a class" << std::endl; } 5 | 6 | struct A { 7 | }; 8 | 9 | int main() { 10 | f(0); 11 | f(0); 12 | } 13 | -------------------------------------------------------------------------------- /Chapter07/is_class2.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | class is_class { 5 | template static char test(int C::*); // selected if C is a class type 6 | template static int test(...); // selected otherwise 7 | public: 8 | //enum { value = sizeof(test(NULL)) == 1 }; 9 | static constexpr bool value = sizeof(test(NULL)) == 1; 10 | }; 11 | 12 | struct A { 13 | }; 14 | 15 | int main() { 16 | std::cout << is_class::value << std::endl; 17 | std::cout << is_class::value << std::endl; 18 | } 19 | -------------------------------------------------------------------------------- /Chapter07/is_class3.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace implementation { 4 | template static char test(int C::*); // selected if C is a class type 5 | template static int test(...); // selected otherwise 6 | } 7 | 8 | template 9 | struct is_class : std::integral_constant(NULL)) == sizeof(char)> {}; 10 | 11 | struct A { 12 | }; 13 | 14 | int main() { 15 | static_assert(!is_class::value, "int is a class?"); 16 | static_assert(is_class::value, "A is not a class?"); 17 | std::cout << is_class::value << std::endl; 18 | std::cout << is_class::value << std::endl; 19 | } 20 | -------------------------------------------------------------------------------- /Chapter07/multiply1.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template auto increase(const T& x, size_t n) -> decltype(T(x) *= n) 4 | { 5 | T y(x); 6 | return y *= n; 7 | } 8 | template auto increase(const T& x, size_t n) -> decltype(x * n) 9 | { 10 | return x * n; 11 | } 12 | 13 | class A { 14 | public: 15 | explicit A(int i) : i_(i) {} 16 | A operator*=(size_t n) { 17 | std::cout << "A*=n" << std::endl; 18 | return A(i_ * n); 19 | } 20 | private: 21 | int i_; 22 | }; 23 | 24 | class B { 25 | public: 26 | explicit B(int i) : i_(i) {} 27 | friend B operator*(const B& lhs, size_t rhs) { 28 | std::cout << "B*n" << std::endl; 29 | return B(lhs.i_ * rhs); 30 | } 31 | private: 32 | int i_; 33 | }; 34 | 35 | class AB { 36 | public: 37 | explicit AB(int i) : i_(i) {} 38 | AB operator*=(size_t n) { 39 | std::cout << "AB*=n" << std::endl; 40 | return AB(i_ * n); 41 | } 42 | friend AB operator*(const AB& lhs, size_t rhs) { 43 | std::cout << "AB*n" << std::endl; 44 | return AB(lhs.i_ * rhs); 45 | } 46 | private: 47 | int i_; 48 | }; 49 | 50 | int main() { 51 | A a(2); increase(a, 3); 52 | B b(2); increase(b, 3); 53 | //AB ab(2); increase(ab, 3); 54 | } 55 | -------------------------------------------------------------------------------- /Chapter07/multiply2.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct yes { char c; }; 4 | struct no { char c; yes c1; }; 5 | 6 | template auto have_star_equal(const T& x, size_t n) -> decltype(T(x) *= n, yes()); 7 | no have_star_equal(...); 8 | 9 | template auto have_star(const T& x, size_t n) -> decltype(x * n, yes()); 10 | no have_star(...); 11 | 12 | template struct increase_helper; 13 | 14 | template struct increase_helper { 15 | static auto f(const T& x, size_t n) { 16 | std::cout << "T *= n, ignoring T * n" << std::endl; 17 | T y(x); 18 | return y *= n; 19 | } 20 | }; 21 | 22 | template struct increase_helper { 23 | static auto f(const T& x, size_t n) { 24 | std::cout << "T *= n" << std::endl; 25 | T y(x); 26 | return y *= n; 27 | } 28 | }; 29 | 30 | template struct increase_helper { 31 | static auto f(const T& x, size_t n) { 32 | std::cout << "T * n" << std::endl; 33 | return x * n; 34 | } 35 | }; 36 | 37 | template struct increase_helper { 38 | static auto f(const T& x, size_t n) { 39 | std::cout << "Cannot increase" << std::endl; 40 | return x; 41 | } 42 | }; 43 | 44 | template auto increase(const T& x, size_t n) { 45 | return increase_helper::f(x, n); 46 | } 47 | 48 | class A { 49 | public: 50 | explicit A(int i) : i_(i) {} 51 | A operator*=(size_t n) { 52 | std::cout << "A*=n" << std::endl; 53 | return A(i_ * n); 54 | } 55 | private: 56 | int i_; 57 | }; 58 | 59 | class B { 60 | public: 61 | explicit B(int i) : i_(i) {} 62 | friend B operator*(const B& lhs, size_t rhs) { 63 | std::cout << "B*n" << std::endl; 64 | return B(lhs.i_ * rhs); 65 | } 66 | private: 67 | int i_; 68 | }; 69 | 70 | class AB { 71 | public: 72 | explicit AB(int i) : i_(i) {} 73 | AB operator*=(size_t n) { 74 | std::cout << "AB*=n" << std::endl; 75 | return AB(i_ * n); 76 | } 77 | friend AB operator*(const AB& lhs, size_t rhs) { 78 | std::cout << "AB*n" << std::endl; 79 | return AB(lhs.i_ * rhs); 80 | } 81 | private: 82 | int i_; 83 | }; 84 | 85 | int main() { 86 | A a(2); increase(a, 3); 87 | B b(2); increase(b, 3); 88 | AB ab(2); increase(ab, 3); 89 | } 90 | -------------------------------------------------------------------------------- /Chapter07/multiply3.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct yes { char c; }; 4 | struct no { char c; yes c1; }; 5 | 6 | template auto have_star_equal(const T& x, size_t n) -> decltype(T(x) *= n, yes()); 7 | no have_star_equal(...); 8 | 9 | template auto have_star(const T& x, size_t n) -> decltype(x * n, yes()); 10 | no have_star(...); 11 | 12 | template struct increase_helper; 13 | 14 | template struct increase_helper { 15 | static auto f(const T& x, size_t n) { 16 | std::cout << "T *= n" << std::endl; 17 | T y(x); 18 | return y *= n; 19 | } 20 | }; 21 | 22 | template struct increase_helper { 23 | static auto f(const T& x, size_t n) { 24 | std::cout << "T * n" << std::endl; 25 | return x * n; 26 | } 27 | }; 28 | 29 | template struct increase_helper { 30 | static auto f(const T& x, size_t n) { 31 | std::cout << "Cannot increase" << std::endl; 32 | return x; 33 | } 34 | }; 35 | 36 | template auto increase(const T& x, size_t n) { 37 | return increase_helper::f(x, n); 38 | } 39 | 40 | class A { 41 | public: 42 | explicit A(int i) : i_(i) {} 43 | A operator*=(size_t n) { 44 | std::cout << "A*=n" << std::endl; 45 | return A(i_ * n); 46 | } 47 | private: 48 | int i_; 49 | }; 50 | 51 | class B { 52 | public: 53 | explicit B(int i) : i_(i) {} 54 | friend B operator*(const B& lhs, size_t rhs) { 55 | std::cout << "B*n" << std::endl; 56 | return B(lhs.i_ * rhs); 57 | } 58 | private: 59 | int i_; 60 | }; 61 | 62 | class AB { 63 | public: 64 | explicit AB(int i) : i_(i) {} 65 | AB operator*=(size_t n) { 66 | std::cout << "AB*=n" << std::endl; 67 | return AB(i_ * n); 68 | } 69 | friend AB operator*(const AB& lhs, size_t rhs) { 70 | std::cout << "AB*n" << std::endl; 71 | return AB(lhs.i_ * rhs); 72 | } 73 | private: 74 | int i_; 75 | }; 76 | 77 | int main() { 78 | A a(2); increase(a, 3); 79 | B b(2); increase(b, 3); 80 | AB ab(2); increase(ab, 3); 81 | } 82 | -------------------------------------------------------------------------------- /Chapter07/no_sfinae1.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template void f(T) { std::cout << "f(T) " << sizeof(T::i) << std::endl; } 4 | void f(...) { std::cout << "f(...)" << std::endl; } 5 | 6 | struct A { 7 | typedef int t; 8 | t i; 9 | }; 10 | 11 | int main() { 12 | // This does not compile: 13 | // SFINAE does not suppress errors in the body of the function! 14 | f(0); 15 | A a{5}; 16 | f(a); 17 | } 18 | -------------------------------------------------------------------------------- /Chapter07/overload1.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void f(int i) { std::cout << "f(int)" << std::endl; } 4 | void f(long i) { std::cout << "f(long)" << std::endl; } 5 | void f(double i) { std::cout << "f(double)" << std::endl; } 6 | 7 | int main() { 8 | f(5); 9 | f(5l); 10 | f(5.0); 11 | //f(5u); 12 | f(5.0f); 13 | } 14 | -------------------------------------------------------------------------------- /Chapter07/overload1a.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void f(int i, int j) { std::cout << "f(int, int)" << std::endl; } 4 | void f(long i, long j) { std::cout << "f(long, long)" << std::endl; } 5 | 6 | int main() { 7 | f(5, 5); 8 | f(5l, 5l); 9 | //f(5, 5l); 10 | f(5, 5.0); 11 | } 12 | -------------------------------------------------------------------------------- /Chapter07/overload1b.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void f(int i) { std::cout << "f(int)" << std::endl; } 4 | void f(long i, long j) { std::cout << "f(long, long)" << std::endl; } 5 | void f(double i, double j = 0) { std::cout << "f(double, double = 0)" << std::endl; } 6 | 7 | int main() { 8 | f(5); 9 | f(5l, 5); 10 | //f(5, 5); 11 | f(5.0); 12 | //f(5l); 13 | f(5.0f); 14 | } 15 | -------------------------------------------------------------------------------- /Chapter07/overload2.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void f(int i) { std::cout << "f(int)" << std::endl; } 4 | void f(long i) { std::cout << "f(long)" << std::endl; } 5 | template void f(T i) { std::cout << "f(T)" << std::endl; } 6 | 7 | int main() { 8 | f(5); 9 | f(5l); 10 | f(5.0); 11 | } 12 | -------------------------------------------------------------------------------- /Chapter07/overload3.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void f(int i) { std::cout << "f(int)" << std::endl; } 4 | template void f(T i) { std::cout << "f(T)" << std::endl; } 5 | template void f(T* i) { std::cout << "f(T*)" << std::endl; } 6 | 7 | int main() { 8 | f(5); 9 | f(5l); 10 | int i = 0; 11 | f(&i); 12 | f(NULL); 13 | f(nullptr); 14 | void* p = &i; 15 | f(p); 16 | } 17 | -------------------------------------------------------------------------------- /Chapter07/overload4.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void f(int i) { std::cout << "f(int)" << std::endl; } 4 | void f(...) { std::cout << "f(...)" << std::endl; } 5 | 6 | struct A {}; 7 | struct B { 8 | operator int() const { return 0; } 9 | }; 10 | 11 | int main() { 12 | f(5); 13 | f(5l); 14 | f(5.0); 15 | A a; 16 | f(a); 17 | B b; 18 | f(b); 19 | } 20 | -------------------------------------------------------------------------------- /Chapter07/overload5.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void f(int i, int j) { std::cout << "f(int, int)" << std::endl; } 4 | template void f(T i, T* p) { std::cout << "f(T, T*)" << std::endl; } 5 | void f(...) { std::cout << "f(...)" << std::endl; } 6 | 7 | int main() { 8 | f(5, 5); 9 | int i; 10 | f(5, &i); 11 | // This compiles but uses the ... overload 12 | // template deduction fails because 5l deduces T as long, &i deduces T as int 13 | f(5l, &i); 14 | f(5l, &i); 15 | // This forces the template overload, but does not compile because &i is int* 16 | f(5l, &i); 17 | } 18 | -------------------------------------------------------------------------------- /Chapter07/overload6.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void f(int i, int j = 0) { std::cout << "f(int, int)" << std::endl; } 4 | template void f(T i, T* p = NULL) { std::cout << "f(T, T*)" << std::endl; } 5 | void f(...) { std::cout << "f(...)" << std::endl; } 6 | 7 | int main() { 8 | int i; 9 | f(5); 10 | f(5l); 11 | f(5, &i); 12 | f(5l, &i); 13 | } 14 | -------------------------------------------------------------------------------- /Chapter07/sfinae1.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template void f(T i, typename T::t& j) { std::cout << "f(T, T::t)" << std::endl; } 4 | template void f(T i, T j) { std::cout << "f(T, T)" << std::endl; } 5 | 6 | struct A { 7 | struct t { int i; }; 8 | t i; 9 | }; 10 | 11 | int main() { 12 | A a{5}; 13 | 14 | f(a, a.i); 15 | f(5, 7); 16 | } 17 | -------------------------------------------------------------------------------- /Chapter07/sfinae1a.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template void f(typename T::t& i) { std::cout << "f(T::t)" << std::endl; } 4 | template void f(T i) { std::cout << "f(T)" << std::endl; } 5 | 6 | struct A { 7 | struct t { int i; }; 8 | t i; 9 | }; 10 | 11 | int main() { 12 | A a{5}; 13 | f(a.i); 14 | f(5); 15 | 16 | f(a.i); 17 | f(5); 18 | } 19 | -------------------------------------------------------------------------------- /Chapter07/sfinae2.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template void f(T* i) { std::cout << "f(T*)" << std::endl; } 4 | template void f(int T::* p) { std::cout << "f(T::*)" << std::endl; } 5 | 6 | struct A { 7 | int i; 8 | int f() { return 0; } 9 | }; 10 | 11 | int main() { 12 | A a; 13 | f(&a.i); 14 | f(&A::i); 15 | } 16 | -------------------------------------------------------------------------------- /Chapter07/sfinae3.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template void f(char(*)[N % 2] = NULL) { std::cout << "N=" << N << " is odd" << std::endl; } 4 | template void f(char(*)[1 - N % 2] = NULL) { std::cout << "N=" << N << " is even" << std::endl; } 5 | 6 | int main() { 7 | f<5>(); 8 | f<8>(); 9 | } 10 | -------------------------------------------------------------------------------- /Chapter07/sfinae4.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template void f(T t, char(*)[N % 2] = NULL) { std::cout << "N=" << N << " is odd" << std::endl; } 4 | template void f(T t, char(*)[1 - N % 2] = NULL) { std::cout << "N=" << N << " is even" << std::endl; } 5 | 6 | struct A { 7 | enum {N = 5}; 8 | }; 9 | struct B { 10 | enum {N = 8}; 11 | }; 12 | 13 | int main() { 14 | A a; 15 | B b; 16 | f(a); 17 | f(b); 18 | } 19 | -------------------------------------------------------------------------------- /Chapter08/not_equal.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template struct not_equal { 4 | bool operator!=(const D& rhs) const { return !static_cast(this)->operator==(rhs); } 5 | }; 6 | 7 | class C : public not_equal { 8 | int i_; 9 | public: 10 | C(int i) : i_(i) {} 11 | bool operator==(const C& rhs) const { return i_ == rhs.i_; } 12 | }; 13 | 14 | int main() { 15 | C c1(1); 16 | C c2(1); 17 | C c3(2); 18 | std::cout << "c1/c2: " << (c1 == c2) << " " << (c1 != c2) << std::endl; 19 | std::cout << "c1/c3: " << (c1 == c3) << " " << (c1 != c3) << std::endl; 20 | } 21 | -------------------------------------------------------------------------------- /Chapter08/not_equal_friend.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template struct not_equal { 4 | friend bool operator!=(const D& lhs, const D& rhs) { return !(lhs == rhs); } 5 | }; 6 | 7 | class C : public not_equal { 8 | int i_; 9 | public: 10 | C(int i) : i_(i) {} 11 | friend bool operator==(const C& lhs, const C& rhs) { return lhs.i_ == rhs.i_; } 12 | }; 13 | 14 | 15 | class D : public not_equal { 16 | int i_; 17 | public: 18 | D(int i) : i_(i) {} 19 | bool operator==(const D& rhs) const { return i_ == rhs.i_; } 20 | }; 21 | 22 | int main() { 23 | C c1(1); 24 | C c2(1); 25 | C c3(2); 26 | std::cout << "c1/c2: " << (c1 == c2) << " " << (c1 != c2) << std::endl; 27 | std::cout << "c1/c3: " << (c1 == c3) << " " << (c1 != c3) << std::endl; 28 | 29 | D d1(1); 30 | D d2(1); 31 | D d3(2); 32 | std::cout << "d1/d2: " << (d1 == d2) << " " << (d1 != d2) << std::endl; 33 | std::cout << "d1/d3: " << (d1 == d3) << " " << (d1 != d3) << std::endl; 34 | } 35 | -------------------------------------------------------------------------------- /Chapter08/registry.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template class registry { 5 | public: 6 | static size_t count; 7 | static D* head; 8 | D* prev; 9 | D* next; 10 | protected: 11 | registry() { 12 | ++count; 13 | prev = nullptr; 14 | next = head; 15 | head = static_cast(this); 16 | if (next) next->prev = head; 17 | } 18 | registry(const registry&) { 19 | ++count; 20 | prev = nullptr; 21 | next = head; 22 | head = static_cast(this); 23 | if (next) next->prev = head; 24 | } 25 | ~registry() { 26 | --count; 27 | if (prev) prev->next = next; 28 | if (next) next->prev = prev; 29 | if (head == this) head = next; 30 | } 31 | 32 | }; 33 | template size_t registry::count(0); 34 | template D* registry::head(nullptr); 35 | 36 | 37 | class C : public registry { 38 | int i_; 39 | public: 40 | C(int i) : i_(i) {} 41 | friend std::ostream& operator<<(std::ostream& out, const C& c) { out << c.i_; return out; } 42 | }; 43 | 44 | class D : public registry { 45 | int i_; 46 | public: 47 | D(int i) : i_(i) {} 48 | friend std::ostream& operator<<(std::ostream& out, const D& d) { out << d.i_; return out; } 49 | }; 50 | 51 | template void report() { 52 | std::cout << "Count: " << T::count; for (const T* p = T::head; p; p = p->next) std::cout << " " << *p; std::cout << std::endl; 53 | } 54 | 55 | int main() { 56 | report(); 57 | C* c4 = nullptr; 58 | { 59 | C c1(1); 60 | report(); 61 | c4 = new C(4); 62 | C c2(2); 63 | D d1(10); 64 | report(); 65 | report(); 66 | } 67 | report(); 68 | C c3(3); 69 | report(); 70 | delete c4; 71 | report(); 72 | report(); 73 | } 74 | 75 | -------------------------------------------------------------------------------- /Chapter08/visitor.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Animal { 5 | public: 6 | enum Type { CAT, DOG, RAT }; 7 | Animal(Type t, const char* n) : type(t), name(n) {} 8 | const Type type; 9 | const char* const name; 10 | }; 11 | 12 | template class GenericVisitor { 13 | public: 14 | template void visit(it from, it to) { 15 | for (it i = from; i != to; ++i) { 16 | this->visit(*i); 17 | } 18 | } 19 | private: 20 | D& derived() { return *static_cast(this); } 21 | void visit(const Animal& animal) { 22 | switch (animal.type) { 23 | case Animal::CAT: 24 | derived().visit_cat(animal); 25 | break; 26 | case Animal::DOG: 27 | derived().visit_dog(animal); 28 | break; 29 | case Animal::RAT: 30 | derived().visit_rat(animal); 31 | break; 32 | } 33 | } 34 | void visit_cat(const Animal& animal) { 35 | std::cout << "Feed the cat " << animal.name << std::endl; 36 | } 37 | void visit_dog(const Animal& animal) { 38 | std::cout << "Wash the dog " << animal.name << std::endl; 39 | } 40 | void visit_rat(const Animal& animal) { 41 | std::cout << "Eeek!" << std::endl; 42 | } 43 | friend D; 44 | GenericVisitor() {} 45 | }; 46 | 47 | class DefaultVisitor : public GenericVisitor { 48 | }; 49 | 50 | class TrainerVisitor : public GenericVisitor { 51 | friend class GenericVisitor; 52 | void visit_dog(const Animal& animal) { 53 | std::cout << "Train the dog " << animal.name << std::endl; 54 | } 55 | }; 56 | 57 | class FelineVisitor : public GenericVisitor { 58 | friend class GenericVisitor; 59 | void visit_cat(const Animal& animal) { 60 | std::cout << "Hiss at the cat " << animal.name << std::endl; 61 | } 62 | void visit_dog(const Animal& animal) { 63 | std::cout << "Hiss at the dog " << animal.name << std::endl; 64 | } 65 | void visit_rat(const Animal& animal) { 66 | std::cout << "Eat the rat " << animal.name << std::endl; 67 | } 68 | }; 69 | 70 | int main() { 71 | std::vector animals {{Animal::CAT, "Fluffy"}, {Animal::DOG, "Fido"}, {Animal::RAT, "Stinky"}}; 72 | DefaultVisitor().visit(animals.begin(), animals.end()); 73 | TrainerVisitor().visit(animals.begin(), animals.end()); 74 | FelineVisitor().visit(animals.begin(), animals.end()); 75 | } 76 | 77 | -------------------------------------------------------------------------------- /Chapter09/city.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using std::cout; 4 | using std::endl; 5 | 6 | class City { 7 | public: 8 | enum center_t { KEEP, PALACE, CITADEL }; 9 | City(size_t number_of_buildings, 10 | size_t number_of_towers, 11 | size_t guard_strength, 12 | center_t center = KEEP, 13 | bool with_forge = false, 14 | bool with_granar = false, 15 | bool has_fresh_wate = false, 16 | bool is_coasta = false, 17 | bool has_fores = false) 18 | {} 19 | }; 20 | 21 | int main() { 22 | City Capital(2, 1, City::KEEP); 23 | } 24 | -------------------------------------------------------------------------------- /Chapter09/cout_chaining.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using std::cout; 4 | using std::endl; 5 | 6 | int main() { 7 | int i = 0, j = 0; 8 | auto& out1 = cout.operator<<(i); 9 | out1.operator<<(j); 10 | } 11 | -------------------------------------------------------------------------------- /Chapter09/named_args1_extra.C: -------------------------------------------------------------------------------- 1 | class Positional { 2 | public: 3 | Positional(bool a = false, bool b = false, bool c = false, bool d = false, 4 | bool e = false, bool f = false, bool g = false, bool h = false); 5 | 6 | operator bool() const { return a_; } 7 | 8 | private: 9 | const bool a_; 10 | const bool b_; 11 | const bool c_; 12 | const bool d_; 13 | const bool e_; 14 | const bool f_; 15 | const bool g_; 16 | const bool h_; 17 | }; 18 | 19 | Positional::Positional(bool a, bool b, bool c, bool d, 20 | bool e, bool f, bool g, bool h) 21 | : a_(a), b_(b), c_(c), d_(d), e_(e), f_(f), g_(g), h_(h) {} 22 | 23 | class Named { 24 | public: 25 | class Options { 26 | public: 27 | Options() : a_(false), b_(false), c_(false), d_(false), 28 | e_(false), f_(false), g_(false), h_(false) {} 29 | Options& SetA(bool a) { a_ = a; return *this; } 30 | Options& SetB(bool b) { b_ = b; return *this; } 31 | Options& SetC(bool c) { c_ = c; return *this; } 32 | Options& SetD(bool d) { d_ = d; return *this; } 33 | Options& SetE(bool e) { e_ = e; return *this; } 34 | Options& SetF(bool f) { f_ = f; return *this; } 35 | Options& SetG(bool g) { g_ = g; return *this; } 36 | Options& SetH(bool h) { h_ = h; return *this; } 37 | 38 | private: 39 | friend class Named; 40 | bool a_; 41 | bool b_; 42 | bool c_; 43 | bool d_; 44 | bool e_; 45 | bool f_; 46 | bool g_; 47 | bool h_; 48 | }; 49 | 50 | Named(Options options); 51 | 52 | operator bool() const { return options_.a_; } 53 | 54 | private: 55 | const Options options_; 56 | }; 57 | 58 | Named::Named(Named::Options options) : options_(options) {} 59 | 60 | class Aggregate { 61 | public: 62 | struct Options { 63 | Options() : a(false), b(false), c(false), d(false), 64 | e(false), f(false), g(false), h(false) {} 65 | bool a; 66 | bool b; 67 | bool c; 68 | bool d; 69 | bool e; 70 | bool f; 71 | bool g; 72 | bool h; 73 | }; 74 | 75 | Aggregate(const Options& options); 76 | 77 | operator bool() const { return options_.a; } 78 | 79 | private: 80 | const Options options_; 81 | }; 82 | 83 | Aggregate::Aggregate(const Aggregate::Options& options) : options_(options) {} 84 | -------------------------------------------------------------------------------- /Chapter09/named_args_extra.C: -------------------------------------------------------------------------------- 1 | class Positional { 2 | public: 3 | Positional(bool a, bool b, bool c, bool d); 4 | 5 | operator bool() const { return a_; } 6 | 7 | private: 8 | const bool a_; 9 | const bool b_; 10 | const bool c_; 11 | const bool d_; 12 | }; 13 | 14 | Positional::Positional(bool a, bool b, bool c, bool d) 15 | : a_(a), b_(b), c_(c), d_(d) {} 16 | 17 | 18 | class Named { 19 | public: 20 | class Options { 21 | public: 22 | Options() : a_(false), b_(false), c_(false), d_(false) {} 23 | Options& SetA(bool a) { a_ = a; return *this; } 24 | Options& SetB(bool b) { b_ = b; return *this; } 25 | Options& SetC(bool c) { c_ = c; return *this; } 26 | Options& SetD(bool d) { d_ = d; return *this; } 27 | 28 | private: 29 | friend class Named; 30 | bool a_; 31 | bool b_; 32 | bool c_; 33 | bool d_; 34 | }; 35 | 36 | Named(Options options); 37 | 38 | operator bool() const { return options_.a_; } 39 | 40 | private: 41 | const Options options_; 42 | }; 43 | 44 | Named::Named(Named::Options options) : options_(options) {} 45 | 46 | class Aggregate { 47 | public: 48 | struct Options { 49 | Options() : a(false), b(false), c(false), d(false) {} 50 | bool a; 51 | bool b; 52 | bool c; 53 | bool d; 54 | }; 55 | 56 | Aggregate(const Options& options); 57 | 58 | operator bool() const { return options_.a; } 59 | 60 | private: 61 | const Options options_; 62 | }; 63 | 64 | Aggregate::Aggregate(const Aggregate::Options& options) : options_(options) {} 65 | -------------------------------------------------------------------------------- /Chapter09/poly_chain1.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using std::cout; 4 | using std::endl; 5 | 6 | class SortedCollection; 7 | class Collection { 8 | public: 9 | Collection() {} 10 | Collection filter(); 11 | SortedCollection sort(); 12 | }; 13 | 14 | class SortedCollection : public Collection { 15 | public: 16 | SortedCollection() {} 17 | SortedCollection(const Collection&) {} 18 | SortedCollection search() { cout << "SortedCollection::search" << endl; return *this; } 19 | SortedCollection median() { cout << "SortedCollection::median" << endl; return *this; } 20 | }; 21 | 22 | Collection Collection::filter() { cout << "Collection::filter" << endl; return *this; } 23 | SortedCollection Collection::sort() { cout << "Collection::sort" << endl; return SortedCollection(*this); } 24 | 25 | int main() { 26 | Collection c; 27 | c.sort().search().filter().median(); 28 | } 29 | -------------------------------------------------------------------------------- /Chapter09/poly_chain2.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using std::cout; 4 | using std::endl; 5 | 6 | class SortedCollection; 7 | class Collection { 8 | public: 9 | Collection() {} 10 | Collection filter(); 11 | SortedCollection sort(); 12 | virtual SortedCollection median(); 13 | }; 14 | 15 | class SortedCollection : public Collection { 16 | public: 17 | SortedCollection() {} 18 | SortedCollection(const Collection&) {} 19 | SortedCollection search() { cout << "SortedCollection::search" << endl; return *this; } 20 | SortedCollection median() { cout << "SortedCollection::median" << endl; return *this; } 21 | }; 22 | 23 | Collection Collection::filter() { cout << "Collection::filter" << endl; return *this; } 24 | SortedCollection Collection::sort() { cout << "Collection::sort" << endl; return SortedCollection(*this); } 25 | SortedCollection Collection::median() { cout << "Collection::median!!!" << endl; return SortedCollection(*this); } 26 | 27 | int main() { 28 | Collection c; 29 | c.sort().search().filter().median(); 30 | } 31 | -------------------------------------------------------------------------------- /Chapter09/poly_chain2a.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using std::cout; 4 | using std::endl; 5 | 6 | class SortedCollection; 7 | class Collection { 8 | public: 9 | Collection() {} 10 | virtual Collection filter(); 11 | SortedCollection sort(); 12 | virtual SortedCollection median(); 13 | }; 14 | 15 | class SortedCollection : public Collection { 16 | public: 17 | SortedCollection() {} 18 | SortedCollection(const Collection&) {} 19 | virtual SortedCollection filter() { cout << "SortedCollection::filter" << endl; return *this; } // Not covariant return type, will not compile! 20 | SortedCollection search() { cout << "SortedCollection::search" << endl; return *this; } 21 | SortedCollection median() { cout << "SortedCollection::median" << endl; return *this; } 22 | }; 23 | 24 | Collection Collection::filter() { cout << "Collection::filter" << endl; return *this; } 25 | SortedCollection Collection::sort() { cout << "Collection::sort" << endl; return SortedCollection(*this); } 26 | SortedCollection Collection::median() { cout << "Collection::median!!!" << endl; return SortedCollection(*this); } 27 | 28 | int main() { 29 | Collection c; 30 | c.sort().search().filter().median(); 31 | } 32 | -------------------------------------------------------------------------------- /Chapter09/poly_chain3.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using std::cout; 4 | using std::endl; 5 | 6 | template 7 | class Collection { 8 | public: 9 | Collection() {} 10 | T filter() { cout << "Collection::filter" << endl; return *static_cast(this); } 11 | T sort() { cout << "Collection::sort" << endl; return T(*this); } 12 | }; 13 | 14 | class SortedCollection : public Collection { 15 | public: 16 | SortedCollection() {} 17 | SortedCollection(const Collection&) {} 18 | SortedCollection search() { cout << "SortedCollection::search" << endl; return *this; } 19 | SortedCollection median() { cout << "SortedCollection::median" << endl; return *this; } 20 | }; 21 | 22 | 23 | int main() { 24 | Collection c; 25 | c.sort().search().filter().median(); 26 | } 27 | -------------------------------------------------------------------------------- /Chapter10/malloc1.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "benchmark/benchmark.h" 6 | 7 | void BM_malloc_free(benchmark::State& state) { 8 | const size_t S = state.range(0); 9 | for (auto _ : state) { 10 | void* p = malloc(S); 11 | benchmark::DoNotOptimize(p); 12 | free(p); 13 | } 14 | state.SetItemsProcessed(state.iterations()); 15 | } 16 | 17 | //BENCHMARK(BM_malloc_free)->Arg(64); 18 | BENCHMARK(BM_malloc_free)->RangeMultiplier(2)->Range(32, 256); 19 | 20 | BENCHMARK_MAIN(); 21 | 22 | -------------------------------------------------------------------------------- /Chapter10/malloc2.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "benchmark/benchmark.h" 6 | 7 | #define REPEAT2(x) x x 8 | #define REPEAT4(x) REPEAT2(x) REPEAT2(x) 9 | #define REPEAT8(x) REPEAT4(x) REPEAT4(x) 10 | #define REPEAT16(x) REPEAT8(x) REPEAT8(x) 11 | #define REPEAT32(x) REPEAT16(x) REPEAT16(x) 12 | #define REPEAT(x) REPEAT32(x) 13 | 14 | void BM_malloc_free(benchmark::State& state) { 15 | const size_t S = state.range(0); 16 | const size_t N = state.range(1); 17 | std::vector v(N); 18 | for (size_t i = 0; i < N; ++i) v[i] = malloc(S); 19 | for (auto _ : state) { 20 | REPEAT({ 21 | void* p = malloc(S); 22 | benchmark::DoNotOptimize(p); 23 | free(p); 24 | }); 25 | } 26 | state.SetItemsProcessed(32*state.iterations()); 27 | for (size_t i = 0; i < N; ++i) free(v[i]); 28 | } 29 | 30 | BENCHMARK(BM_malloc_free)->RangeMultiplier(2)->Ranges({{32, 256}, {1<<15, 1<<15}}); 31 | 32 | BENCHMARK_MAIN(); 33 | 34 | -------------------------------------------------------------------------------- /Chapter10/malloc3.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include "benchmark/benchmark.h" 7 | 8 | #define REPEAT2(x) x x 9 | #define REPEAT4(x) REPEAT2(x) REPEAT2(x) 10 | #define REPEAT8(x) REPEAT4(x) REPEAT4(x) 11 | #define REPEAT16(x) REPEAT8(x) REPEAT8(x) 12 | #define REPEAT32(x) REPEAT16(x) REPEAT16(x) 13 | #define REPEAT(x) REPEAT32(x) 14 | 15 | void BM_malloc_free(benchmark::State& state) { 16 | const size_t S = state.range(0); 17 | const size_t N = state.range(1); 18 | std::vector v(N); 19 | for (size_t i = 0; i < N; ++i) v[i] = malloc(S); 20 | for (auto _ : state) { 21 | REPEAT({ 22 | void* p = malloc(S); 23 | benchmark::DoNotOptimize(p); 24 | free(p); 25 | }); 26 | } 27 | state.SetItemsProcessed(32*state.iterations()); 28 | for (size_t i = 0; i < N; ++i) free(v[i]); 29 | } 30 | 31 | static const long max_threads = sysconf(_SC_NPROCESSORS_CONF); 32 | BENCHMARK(BM_malloc_free)->RangeMultiplier(2)->Ranges({{32, 256}, {1<<15, 1<<15}})->ThreadRange(1, max_threads); 33 | 34 | BENCHMARK_MAIN(); 35 | 36 | -------------------------------------------------------------------------------- /Chapter10/vector1.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "benchmark/benchmark.h" 4 | 5 | class simple_vector { 6 | public: 7 | simple_vector() : n_(), p_() {} 8 | simple_vector(std::initializer_list il) : n_(il.size()), p_(static_cast(malloc(sizeof(int)*n_))) { 9 | int* p = p_; 10 | for (auto x : il) *p++ = x; 11 | } 12 | ~simple_vector() { 13 | free(p_); 14 | } 15 | size_t size() const { return n_; } 16 | private: 17 | size_t n_; 18 | int* p_; 19 | }; 20 | 21 | class small_vector { 22 | public: 23 | small_vector() : n_(), p_() {} 24 | small_vector(std::initializer_list il) : n_(il.size()), p_(n_ < sizeof(buf_)/sizeof(buf_[0]) ? buf_ : static_cast(malloc(sizeof(int)*n_))) { 25 | int* p = p_; 26 | for (auto x : il) *p++ = x; 27 | } 28 | ~small_vector() { 29 | if (p_ != buf_) free(p_); 30 | } 31 | private: 32 | size_t n_; 33 | int* p_; 34 | int buf_[16]; 35 | }; 36 | 37 | #define REPEAT2(x) x x 38 | #define REPEAT4(x) REPEAT2(x) REPEAT2(x) 39 | #define REPEAT8(x) REPEAT4(x) REPEAT4(x) 40 | #define REPEAT16(x) REPEAT8(x) REPEAT8(x) 41 | #define REPEAT32(x) REPEAT16(x) REPEAT16(x) 42 | #define REPEAT(x) REPEAT32(x) 43 | 44 | template 45 | void BM_vector_create_short(benchmark::State& state) { 46 | std::initializer_list il { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 }; 47 | for (auto _ : state) { 48 | REPEAT({ T v(il); benchmark::DoNotOptimize(v); }) 49 | } 50 | state.SetItemsProcessed(32*state.iterations()); 51 | } 52 | 53 | template 54 | void BM_vector_create_long(benchmark::State& state) { 55 | std::initializer_list il { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199 }; 56 | for (auto _ : state) { 57 | REPEAT({ T v(il); benchmark::DoNotOptimize(v); }) 58 | } 59 | state.SetItemsProcessed(32*state.iterations()); 60 | } 61 | 62 | BENCHMARK_TEMPLATE1(BM_vector_create_short, simple_vector); 63 | BENCHMARK_TEMPLATE1(BM_vector_create_short, small_vector); 64 | BENCHMARK_TEMPLATE1(BM_vector_create_long, simple_vector); 65 | BENCHMARK_TEMPLATE1(BM_vector_create_long, small_vector); 66 | 67 | BENCHMARK_MAIN(); 68 | 69 | -------------------------------------------------------------------------------- /Chapter10/vector2.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | #include "benchmark/benchmark.h" 6 | 7 | class simple_vector { 8 | public: 9 | simple_vector() : n_(), p_() {} 10 | simple_vector(std::initializer_list il) : n_(il.size()), p_(static_cast(malloc(sizeof(int)*n_))) { 11 | int* p = p_; 12 | for (auto x : il) *p++ = x; 13 | } 14 | ~simple_vector() { 15 | free(p_); 16 | } 17 | size_t size() const { return n_; } 18 | private: 19 | size_t n_; 20 | int* p_; 21 | }; 22 | 23 | class small_vector { 24 | public: 25 | small_vector() { short_.n = 0; } 26 | small_vector(std::initializer_list il) { 27 | int* p; 28 | if (il.size() < sizeof(short_.buf)/sizeof(short_.buf[0])) { 29 | short_.n = il.size(); 30 | p = short_.buf; 31 | } else { 32 | short_.n = UCHAR_MAX; 33 | long_.n = il.size(); 34 | p = long_.p = static_cast(malloc(sizeof(int)*long_.n)); 35 | } 36 | for (auto x : il) *p++ = x; 37 | } 38 | ~small_vector() { 39 | if (short_.n == UCHAR_MAX) free(long_.p); 40 | } 41 | private: 42 | union { 43 | struct { 44 | size_t n; 45 | int* p; 46 | } long_; 47 | struct { 48 | int buf[15]; 49 | unsigned char n; 50 | } short_; 51 | }; 52 | }; 53 | 54 | #define REPEAT2(x) x x 55 | #define REPEAT4(x) REPEAT2(x) REPEAT2(x) 56 | #define REPEAT8(x) REPEAT4(x) REPEAT4(x) 57 | #define REPEAT16(x) REPEAT8(x) REPEAT8(x) 58 | #define REPEAT32(x) REPEAT16(x) REPEAT16(x) 59 | #define REPEAT(x) REPEAT32(x) 60 | 61 | template 62 | void BM_vector_create_short(benchmark::State& state) { 63 | std::initializer_list il { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 }; 64 | for (auto _ : state) { 65 | REPEAT({ T v(il); benchmark::DoNotOptimize(v); }) 66 | } 67 | state.SetItemsProcessed(32*state.iterations()); 68 | } 69 | 70 | template 71 | void BM_vector_create_long(benchmark::State& state) { 72 | std::initializer_list il { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199 }; 73 | for (auto _ : state) { 74 | REPEAT({ T v(il); benchmark::DoNotOptimize(v); }) 75 | } 76 | state.SetItemsProcessed(32*state.iterations()); 77 | } 78 | 79 | BENCHMARK_TEMPLATE1(BM_vector_create_short, simple_vector); 80 | BENCHMARK_TEMPLATE1(BM_vector_create_short, small_vector); 81 | BENCHMARK_TEMPLATE1(BM_vector_create_long, simple_vector); 82 | BENCHMARK_TEMPLATE1(BM_vector_create_long, small_vector); 83 | 84 | BENCHMARK_MAIN(); 85 | 86 | -------------------------------------------------------------------------------- /Chapter11/01_bad.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | enum Outcome { SUCCESS, FAIL_RETURN, FAIL_THROW }; 4 | 5 | // Demo disk storage, does nothing useful but may throw exception. 6 | class Storage { 7 | public: 8 | Storage() : i_(0) {} 9 | bool insert(int i, Outcome outcome) { 10 | if (outcome == FAIL_THROW) throw 0; 11 | if (outcome == FAIL_RETURN) return false; 12 | i_ = i; 13 | return true; 14 | } 15 | int get() const { return i_; } 16 | private: 17 | int i_; 18 | }; 19 | 20 | // Demo memory index, does nothing useful but may throw exception. 21 | class Index { 22 | public: 23 | Index() : i_(0) {} 24 | bool insert(int i, Outcome outcome) { 25 | if (outcome == FAIL_THROW) throw 0; 26 | if (outcome == FAIL_RETURN) return false; 27 | i_ = i; 28 | return true; 29 | } 30 | int get() const { return i_; } 31 | private: 32 | int i_; 33 | }; 34 | 35 | int main() { 36 | Storage S; 37 | Index I; 38 | try { 39 | S.insert(42, SUCCESS); 40 | I.insert(42, FAIL_THROW); 41 | } catch (...) { 42 | } 43 | 44 | if (S.get() != I.get()) std::cout << "Inconsistent state: " << S.get() << " != " << I.get() << std::endl; 45 | } 46 | -------------------------------------------------------------------------------- /Chapter11/02_trycatch.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | enum Outcome { SUCCESS, FAIL_RETURN, FAIL_THROW }; 4 | 5 | // Demo disk storage, does nothing useful but may throw exception. 6 | class Storage { 7 | public: 8 | Storage() : i_(0) {} 9 | bool insert(int i, Outcome outcome) { 10 | if (outcome == FAIL_THROW) throw 0; 11 | if (outcome == FAIL_RETURN) return false; 12 | i1_ = i_; i_ = i; 13 | return true; 14 | } 15 | void undo() { 16 | i_ = i1_; 17 | } 18 | int get() const { return i_; } 19 | private: 20 | int i_; 21 | int i1_; 22 | }; 23 | 24 | // Demo memory index, does nothing useful but may throw exception. 25 | class Index { 26 | public: 27 | Index() : i_(0) {} 28 | bool insert(int i, Outcome outcome) { 29 | if (outcome == FAIL_THROW) throw 0; 30 | if (outcome == FAIL_RETURN) return false; 31 | i1_ = i_; i_ = i; 32 | return true; 33 | } 34 | void undo() { 35 | i_ = i1_; 36 | } 37 | int get() const { return i_; } 38 | private: 39 | int i_; 40 | int i1_; 41 | }; 42 | 43 | int main() { 44 | Storage S; 45 | Index I; 46 | try { 47 | S.insert(42, SUCCESS); 48 | try { 49 | I.insert(42, FAIL_THROW); 50 | } catch (...) { 51 | S.undo(); 52 | } 53 | } catch (...) { 54 | } 55 | 56 | if (S.get() != I.get()) std::cout << "Inconsistent state: " << S.get() << " != " << I.get() << std::endl; 57 | else std::cout << "Database OK" << std::endl; 58 | } 59 | -------------------------------------------------------------------------------- /Chapter11/02a_trycatch_cleanup.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | enum Outcome { SUCCESS, FAIL_RETURN, FAIL_THROW }; 4 | 5 | // Demo disk storage, does nothing useful but may throw exception. 6 | class Storage { 7 | public: 8 | Storage() : i_(0), finalized_(false) {} 9 | bool insert(int i, Outcome outcome) { 10 | if (outcome == FAIL_THROW) throw 0; 11 | if (outcome == FAIL_RETURN) return false; 12 | i1_ = i_; i_ = i; 13 | return true; 14 | } 15 | void undo() { 16 | i_ = i1_; 17 | } 18 | void finalize() { finalized_ = true; } 19 | bool finalized() const { return finalized_; } 20 | int get() const { return i_; } 21 | private: 22 | int i_; 23 | int i1_; 24 | bool finalized_; 25 | }; 26 | 27 | // Demo memory index, does nothing useful but may throw exception. 28 | class Index { 29 | public: 30 | Index() : i_(0) {} 31 | bool insert(int i, Outcome outcome) { 32 | if (outcome == FAIL_THROW) throw 0; 33 | if (outcome == FAIL_RETURN) return false; 34 | i1_ = i_; i_ = i; 35 | return true; 36 | } 37 | void undo() { 38 | i_ = i1_; 39 | } 40 | int get() const { return i_; } 41 | private: 42 | int i_; 43 | int i1_; 44 | }; 45 | 46 | int main() { 47 | Storage S; 48 | Index I; 49 | try { 50 | S.insert(42, SUCCESS); 51 | try { 52 | I.insert(42, FAIL_THROW); 53 | } catch (...) { 54 | S.undo(); 55 | } 56 | S.finalize(); 57 | } catch (...) { 58 | } 59 | 60 | if (S.get() != I.get()) std::cout << "Inconsistent state: " << S.get() << " != " << I.get() << std::endl; 61 | else if (!S.finalized()) std::cout << "Not finalized" << std::endl; 62 | else std::cout << "Database OK" << std::endl; 63 | } 64 | -------------------------------------------------------------------------------- /Chapter11/02b_trycatch_raiicleanup.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | enum Outcome { SUCCESS, FAIL_RETURN, FAIL_THROW }; 4 | 5 | // Demo disk storage, does nothing useful but may throw exception. 6 | class Storage { 7 | public: 8 | Storage() : i_(0), finalized_(false) {} 9 | bool insert(int i, Outcome outcome) { 10 | if (outcome == FAIL_THROW) throw 0; 11 | if (outcome == FAIL_RETURN) return false; 12 | i1_ = i_; i_ = i; 13 | return true; 14 | } 15 | void undo() { 16 | i_ = i1_; 17 | } 18 | void finalize() { finalized_ = true; } 19 | bool finalized() const { return finalized_; } 20 | int get() const { return i_; } 21 | private: 22 | int i_; 23 | int i1_; 24 | bool finalized_; 25 | }; 26 | 27 | // Demo memory index, does nothing useful but may throw exception. 28 | class Index { 29 | public: 30 | Index() : i_(0) {} 31 | bool insert(int i, Outcome outcome) { 32 | if (outcome == FAIL_THROW) throw 0; 33 | if (outcome == FAIL_RETURN) return false; 34 | i1_ = i_; i_ = i; 35 | return true; 36 | } 37 | void undo() { 38 | i_ = i1_; 39 | } 40 | int get() const { return i_; } 41 | private: 42 | int i_; 43 | int i1_; 44 | }; 45 | 46 | int main() { 47 | Storage S; 48 | Index I; 49 | class StorageFinalizer { 50 | public: 51 | StorageFinalizer(Storage& S) : S_(S) {} 52 | ~StorageFinalizer() { S_.finalize(); } 53 | private: 54 | Storage& S_; 55 | }; 56 | try { 57 | S.insert(42, SUCCESS); 58 | try { 59 | I.insert(42, FAIL_THROW); 60 | } catch (...) { 61 | S.undo(); 62 | } 63 | S.finalize(); 64 | } catch (...) { 65 | } 66 | 67 | if (S.get() != I.get()) std::cout << "Inconsistent state: " << S.get() << " != " << I.get() << std::endl; 68 | else if (!S.finalized()) std::cout << "Not finalized" << std::endl; 69 | else std::cout << "Database OK" << std::endl; 70 | } 71 | -------------------------------------------------------------------------------- /Chapter11/03_raii.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | enum Outcome { SUCCESS, FAIL_RETURN, FAIL_THROW }; 4 | 5 | // Demo disk storage, does nothing useful but may throw exception. 6 | class Storage { 7 | public: 8 | Storage() : i_(0) {} 9 | bool insert(int i, Outcome outcome) { 10 | if (outcome == FAIL_THROW) throw 0; 11 | if (outcome == FAIL_RETURN) return false; 12 | i1_ = i_; i_ = i; 13 | return true; 14 | } 15 | void undo() { 16 | i_ = i1_; 17 | } 18 | int get() const { return i_; } 19 | private: 20 | int i_; 21 | int i1_; 22 | }; 23 | 24 | // Demo memory index, does nothing useful but may throw exception. 25 | class Index { 26 | public: 27 | Index() : i_(0) {} 28 | bool insert(int i, Outcome outcome) { 29 | if (outcome == FAIL_THROW) throw 0; 30 | if (outcome == FAIL_RETURN) return false; 31 | i1_ = i_; i_ = i; 32 | return true; 33 | } 34 | void undo() { 35 | i_ = i1_; 36 | } 37 | int get() const { return i_; } 38 | private: 39 | int i_; 40 | int i1_; 41 | }; 42 | 43 | int main() { 44 | Storage S; 45 | Index I; 46 | class StorageGuard { 47 | public: 48 | StorageGuard(Storage& S) : S_(S), commit_(false) {} 49 | ~StorageGuard() { if (!commit_) S_.undo(); } 50 | void commit() noexcept { commit_ = true; } 51 | private: 52 | Storage& S_; 53 | bool commit_; 54 | StorageGuard(const StorageGuard&) = delete; 55 | StorageGuard& operator=(const StorageGuard&) = delete; 56 | }; 57 | try { 58 | S.insert(42, SUCCESS); 59 | StorageGuard SG(S); 60 | I.insert(42, FAIL_THROW); 61 | SG.commit(); 62 | } catch (...) { 63 | } 64 | 65 | if (S.get() != I.get()) std::cout << "Inconsistent state: " << S.get() << " != " << I.get() << std::endl; 66 | else std::cout << "Database OK" << std::endl; 67 | } 68 | -------------------------------------------------------------------------------- /Chapter11/04_scopeguard_basic.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | enum Outcome { SUCCESS, FAIL_RETURN, FAIL_THROW }; 4 | 5 | // Demo disk storage, does nothing useful but may throw exception. 6 | class Storage { 7 | public: 8 | Storage() : i_(0) {} 9 | bool insert(int i, Outcome outcome) { 10 | if (outcome == FAIL_THROW) throw 0; 11 | if (outcome == FAIL_RETURN) return false; 12 | i1_ = i_; i_ = i; 13 | return true; 14 | } 15 | void undo() { 16 | i_ = i1_; 17 | } 18 | int get() const { return i_; } 19 | private: 20 | int i_; 21 | int i1_; 22 | }; 23 | void undo(Storage& S) { S.undo(); } 24 | 25 | // Demo memory index, does nothing useful but may throw exception. 26 | class Index { 27 | public: 28 | Index() : i_(0) {} 29 | bool insert(int i, Outcome outcome) { 30 | if (outcome == FAIL_THROW) throw 0; 31 | if (outcome == FAIL_RETURN) return false; 32 | i1_ = i_; i_ = i; 33 | return true; 34 | } 35 | void undo() { 36 | i_ = i1_; 37 | } 38 | int get() const { return i_; } 39 | private: 40 | int i_; 41 | int i1_; 42 | }; 43 | 44 | class ScopeGuardImplBase { 45 | public: 46 | ScopeGuardImplBase() : commit_(false) {} 47 | void commit() const noexcept { commit_ = true; } 48 | 49 | protected: 50 | ScopeGuardImplBase(const ScopeGuardImplBase& other) : commit_(other.commit_) { other.commit(); } 51 | ~ScopeGuardImplBase() {} 52 | mutable bool commit_; 53 | 54 | private: 55 | ScopeGuardImplBase& operator=(const ScopeGuardImplBase&) = delete; 56 | }; 57 | 58 | template 59 | class ScopeGuardImpl : public ScopeGuardImplBase { 60 | public: 61 | ScopeGuardImpl(const Func& func, Arg& arg) : func_(func), arg_(arg) {} 62 | ~ScopeGuardImpl() { if (!commit_) func_(arg_); } 63 | private: 64 | const Func& func_; 65 | Arg& arg_; 66 | }; 67 | 68 | template 69 | ScopeGuardImpl MakeGuard(const Func& func, Arg& arg) { 70 | return ScopeGuardImpl(func, arg); 71 | } 72 | 73 | int main() { 74 | Storage S; 75 | Index I; 76 | try { 77 | S.insert(42, SUCCESS); 78 | const ScopeGuardImplBase& SG = MakeGuard(undo, S); 79 | I.insert(42, FAIL_THROW); 80 | SG.commit(); // This is why commit_ is mutable 81 | } catch (...) { 82 | } 83 | 84 | if (S.get() != I.get()) std::cout << "Inconsistent state: " << S.get() << " != " << I.get() << std::endl; 85 | else std::cout << "Database OK" << std::endl; 86 | } 87 | -------------------------------------------------------------------------------- /Chapter11/04a_scopeguard_basic_typedef.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | enum Outcome { SUCCESS, FAIL_RETURN, FAIL_THROW }; 4 | 5 | // Demo disk storage, does nothing useful but may throw exception. 6 | class Storage { 7 | public: 8 | Storage() : i_(0) {} 9 | bool insert(int i, Outcome outcome) { 10 | if (outcome == FAIL_THROW) throw 0; 11 | if (outcome == FAIL_RETURN) return false; 12 | i1_ = i_; i_ = i; 13 | return true; 14 | } 15 | void undo() { 16 | i_ = i1_; 17 | } 18 | int get() const { return i_; } 19 | private: 20 | int i_; 21 | int i1_; 22 | }; 23 | void undo(Storage& S) { S.undo(); } 24 | 25 | // Demo memory index, does nothing useful but may throw exception. 26 | class Index { 27 | public: 28 | Index() : i_(0) {} 29 | bool insert(int i, Outcome outcome) { 30 | if (outcome == FAIL_THROW) throw 0; 31 | if (outcome == FAIL_RETURN) return false; 32 | i1_ = i_; i_ = i; 33 | return true; 34 | } 35 | void undo() { 36 | i_ = i1_; 37 | } 38 | int get() const { return i_; } 39 | private: 40 | int i_; 41 | int i1_; 42 | }; 43 | 44 | class ScopeGuardImplBase { 45 | public: 46 | ScopeGuardImplBase() : commit_(false) {} 47 | void commit() const noexcept { commit_ = true; } 48 | 49 | protected: 50 | ScopeGuardImplBase(const ScopeGuardImplBase& other) : commit_(other.commit_) { other.commit(); } 51 | ~ScopeGuardImplBase() {} 52 | mutable bool commit_; 53 | 54 | private: 55 | ScopeGuardImplBase& operator=(const ScopeGuardImplBase&) = delete; 56 | }; 57 | typedef const ScopeGuardImplBase& ScopeGuard; 58 | 59 | template 60 | class ScopeGuardImpl : public ScopeGuardImplBase { 61 | public: 62 | ScopeGuardImpl(const Func& func, Arg& arg) : func_(func), arg_(arg) {} 63 | ~ScopeGuardImpl() { if (!commit_) func_(arg_); } 64 | private: 65 | const Func& func_; 66 | Arg& arg_; 67 | }; 68 | 69 | template 70 | ScopeGuardImpl MakeGuard(const Func& func, Arg& arg) { 71 | return ScopeGuardImpl(func, arg); 72 | } 73 | 74 | int main() { 75 | Storage S; 76 | Index I; 77 | try { 78 | S.insert(42, SUCCESS); 79 | ScopeGuard SG = MakeGuard(undo, S); 80 | I.insert(42, FAIL_THROW); 81 | SG.commit(); 82 | } catch (...) { 83 | } 84 | 85 | if (S.get() != I.get()) std::cout << "Inconsistent state: " << S.get() << " != " << I.get() << std::endl; 86 | else std::cout << "Database OK" << std::endl; 87 | } 88 | -------------------------------------------------------------------------------- /Chapter11/05_scopeguard_basic_move.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | enum Outcome { SUCCESS, FAIL_RETURN, FAIL_THROW }; 4 | 5 | // Demo disk storage, does nothing useful but may throw exception. 6 | class Storage { 7 | public: 8 | Storage() : i_(0) {} 9 | bool insert(int i, Outcome outcome) { 10 | if (outcome == FAIL_THROW) throw 0; 11 | if (outcome == FAIL_RETURN) return false; 12 | i1_ = i_; i_ = i; 13 | return true; 14 | } 15 | void undo() { 16 | i_ = i1_; 17 | } 18 | int get() const { return i_; } 19 | private: 20 | int i_; 21 | int i1_; 22 | }; 23 | void undo(Storage& S) { S.undo(); } 24 | 25 | // Demo memory index, does nothing useful but may throw exception. 26 | class Index { 27 | public: 28 | Index() : i_(0) {} 29 | bool insert(int i, Outcome outcome) { 30 | if (outcome == FAIL_THROW) throw 0; 31 | if (outcome == FAIL_RETURN) return false; 32 | i1_ = i_; i_ = i; 33 | return true; 34 | } 35 | void undo() { 36 | i_ = i1_; 37 | } 38 | int get() const { return i_; } 39 | private: 40 | int i_; 41 | int i1_; 42 | }; 43 | 44 | class ScopeGuardImplBase { 45 | public: 46 | ScopeGuardImplBase() : commit_(false) {} 47 | void commit() const noexcept { commit_ = true; } 48 | 49 | protected: 50 | ScopeGuardImplBase(ScopeGuardImplBase&& other) : commit_(other.commit_) { other.commit(); } 51 | ~ScopeGuardImplBase() {} 52 | mutable bool commit_; 53 | 54 | private: 55 | ScopeGuardImplBase& operator=(const ScopeGuardImplBase&) = delete; 56 | }; 57 | typedef const ScopeGuardImplBase& ScopeGuard; 58 | 59 | template 60 | class ScopeGuardImpl : public ScopeGuardImplBase { 61 | public: 62 | ScopeGuardImpl(const Func& func, Arg& arg) : func_(func), arg_(arg) {} 63 | ~ScopeGuardImpl() { if (!commit_) func_(arg_); } 64 | ScopeGuardImpl(ScopeGuardImpl&& other) : ScopeGuardImplBase(std::move(other)), func_(other.func_), arg_(other.arg_) {} 65 | private: 66 | const Func& func_; 67 | Arg& arg_; 68 | }; 69 | 70 | template 71 | ScopeGuardImpl MakeGuard(const Func& func, Arg& arg) { 72 | return ScopeGuardImpl(func, arg); 73 | } 74 | 75 | int main() { 76 | Storage S; 77 | Index I; 78 | try { 79 | S.insert(42, SUCCESS); 80 | ScopeGuard SG = MakeGuard(undo, S); 81 | I.insert(42, FAIL_THROW); 82 | SG.commit(); 83 | } catch (...) { 84 | } 85 | 86 | if (S.get() != I.get()) std::cout << "Inconsistent state: " << S.get() << " != " << I.get() << std::endl; 87 | else std::cout << "Database OK" << std::endl; 88 | } 89 | -------------------------------------------------------------------------------- /Chapter11/05a_scopeguard_basic_move_cpp14.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | enum Outcome { SUCCESS, FAIL_RETURN, FAIL_THROW }; 4 | 5 | // Demo disk storage, does nothing useful but may throw exception. 6 | class Storage { 7 | public: 8 | Storage() : i_(0) {} 9 | bool insert(int i, Outcome outcome) { 10 | if (outcome == FAIL_THROW) throw 0; 11 | if (outcome == FAIL_RETURN) return false; 12 | i1_ = i_; i_ = i; 13 | return true; 14 | } 15 | void undo() { 16 | i_ = i1_; 17 | } 18 | int get() const { return i_; } 19 | private: 20 | int i_; 21 | int i1_; 22 | }; 23 | void undo(Storage& S) { S.undo(); } 24 | 25 | // Demo memory index, does nothing useful but may throw exception. 26 | class Index { 27 | public: 28 | Index() : i_(0) {} 29 | bool insert(int i, Outcome outcome) { 30 | if (outcome == FAIL_THROW) throw 0; 31 | if (outcome == FAIL_RETURN) return false; 32 | i1_ = i_; i_ = i; 33 | return true; 34 | } 35 | void undo() { 36 | i_ = i1_; 37 | } 38 | int get() const { return i_; } 39 | private: 40 | int i_; 41 | int i1_; 42 | }; 43 | 44 | class ScopeGuardImplBase { 45 | public: 46 | ScopeGuardImplBase() : commit_(false) {} 47 | void commit() const noexcept { commit_ = true; } 48 | 49 | protected: 50 | ScopeGuardImplBase(ScopeGuardImplBase&& other) : commit_(other.commit_) { other.commit(); } 51 | ~ScopeGuardImplBase() {} 52 | mutable bool commit_; 53 | 54 | private: 55 | ScopeGuardImplBase& operator=(const ScopeGuardImplBase&) = delete; 56 | }; 57 | typedef const ScopeGuardImplBase& ScopeGuard; 58 | 59 | template 60 | class ScopeGuardImpl : public ScopeGuardImplBase { 61 | public: 62 | ScopeGuardImpl(const Func& func, Arg& arg) : func_(func), arg_(arg) {} 63 | ~ScopeGuardImpl() { if (!commit_) func_(arg_); } 64 | ScopeGuardImpl(ScopeGuardImpl&& other) : ScopeGuardImplBase(std::move(other)), func_(other.func_), arg_(other.arg_) {} 65 | private: 66 | const Func& func_; 67 | Arg& arg_; 68 | }; 69 | 70 | template 71 | auto MakeGuard(const Func& func, Arg& arg) { 72 | return ScopeGuardImpl(func, arg); 73 | } 74 | 75 | int main() { 76 | Storage S; 77 | Index I; 78 | try { 79 | S.insert(42, SUCCESS); 80 | ScopeGuard SG = MakeGuard(undo, S); 81 | I.insert(42, FAIL_THROW); 82 | SG.commit(); 83 | } catch (...) { 84 | } 85 | 86 | if (S.get() != I.get()) std::cout << "Inconsistent state: " << S.get() << " != " << I.get() << std::endl; 87 | else std::cout << "Database OK" << std::endl; 88 | } 89 | -------------------------------------------------------------------------------- /Chapter11/06_scopeguard_obj.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | enum Outcome { SUCCESS, FAIL_RETURN, FAIL_THROW }; 4 | 5 | // Demo disk storage, does nothing useful but may throw exception. 6 | class Storage { 7 | public: 8 | Storage() : i_(0) {} 9 | bool insert(int i, Outcome outcome) { 10 | if (outcome == FAIL_THROW) throw 0; 11 | if (outcome == FAIL_RETURN) return false; 12 | i1_ = i_; i_ = i; 13 | return true; 14 | } 15 | void undo() { 16 | i_ = i1_; 17 | } 18 | int get() const { return i_; } 19 | private: 20 | int i_; 21 | int i1_; 22 | }; 23 | 24 | // Demo memory index, does nothing useful but may throw exception. 25 | class Index { 26 | public: 27 | Index() : i_(0) {} 28 | bool insert(int i, Outcome outcome) { 29 | if (outcome == FAIL_THROW) throw 0; 30 | if (outcome == FAIL_RETURN) return false; 31 | i1_ = i_; i_ = i; 32 | return true; 33 | } 34 | void undo() { 35 | i_ = i1_; 36 | } 37 | int get() const { return i_; } 38 | private: 39 | int i_; 40 | int i1_; 41 | }; 42 | 43 | class ScopeGuardImplBase { 44 | public: 45 | ScopeGuardImplBase() : commit_(false) {} 46 | void commit() const noexcept { commit_ = true; } 47 | 48 | protected: 49 | ScopeGuardImplBase(ScopeGuardImplBase&& other) : commit_(other.commit_) { other.commit(); } 50 | ~ScopeGuardImplBase() {} 51 | mutable bool commit_; 52 | 53 | private: 54 | ScopeGuardImplBase& operator=(const ScopeGuardImplBase&) = delete; 55 | }; 56 | typedef const ScopeGuardImplBase& ScopeGuard; 57 | 58 | template 59 | class ScopeGuardImpl : public ScopeGuardImplBase { 60 | public: 61 | ScopeGuardImpl(const MemFunc& memfunc, Obj& obj) : memfunc_(memfunc), obj_(obj) {} 62 | ~ScopeGuardImpl() { if (!commit_) (obj_.*memfunc_)(); } 63 | ScopeGuardImpl(ScopeGuardImpl&& other) : ScopeGuardImplBase(std::move(other)), memfunc_(other.memfunc_), obj_(other.obj_) {} 64 | private: 65 | const MemFunc& memfunc_; 66 | Obj& obj_; 67 | }; 68 | 69 | template 70 | ScopeGuardImpl MakeGuard(const MemFunc& memfunc, Obj& obj) { 71 | return ScopeGuardImpl(memfunc, obj); 72 | } 73 | 74 | int main() { 75 | Storage S; 76 | Index I; 77 | try { 78 | S.insert(42, SUCCESS); 79 | ScopeGuard SG = MakeGuard(&Storage::undo, S); 80 | I.insert(42, FAIL_THROW); 81 | SG.commit(); 82 | } catch (...) { 83 | } 84 | 85 | if (S.get() != I.get()) std::cout << "Inconsistent state: " << S.get() << " != " << I.get() << std::endl; 86 | else std::cout << "Database OK" << std::endl; 87 | } 88 | -------------------------------------------------------------------------------- /Chapter11/07_scopeguard_lambda.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | enum Outcome { SUCCESS, FAIL_RETURN, FAIL_THROW }; 4 | 5 | // Demo disk storage, does nothing useful but may throw exception. 6 | class Storage { 7 | public: 8 | Storage() : i_(0) {} 9 | bool insert(int i, Outcome outcome) { 10 | if (outcome == FAIL_THROW) throw 0; 11 | if (outcome == FAIL_RETURN) return false; 12 | i1_ = i_; i_ = i; 13 | return true; 14 | } 15 | void undo() { 16 | i_ = i1_; 17 | } 18 | int get() const { return i_; } 19 | private: 20 | int i_; 21 | int i1_; 22 | }; 23 | 24 | // Demo memory index, does nothing useful but may throw exception. 25 | class Index { 26 | public: 27 | Index() : i_(0) {} 28 | bool insert(int i, Outcome outcome) { 29 | if (outcome == FAIL_THROW) throw 0; 30 | if (outcome == FAIL_RETURN) return false; 31 | i1_ = i_; i_ = i; 32 | return true; 33 | } 34 | void undo() { 35 | i_ = i1_; 36 | } 37 | int get() const { return i_; } 38 | private: 39 | int i_; 40 | int i1_; 41 | }; 42 | 43 | class ScopeGuardBase { 44 | public: 45 | ScopeGuardBase() : commit_(false) {} 46 | void commit() const noexcept { commit_ = true; } 47 | 48 | protected: 49 | ScopeGuardBase(ScopeGuardBase&& other) : commit_(other.commit_) { other.commit(); } 50 | ~ScopeGuardBase() {} 51 | mutable bool commit_; 52 | 53 | private: 54 | ScopeGuardBase& operator=(const ScopeGuardBase&) = delete; 55 | }; 56 | 57 | template 58 | class ScopeGuard : public ScopeGuardBase { 59 | public: 60 | ScopeGuard(Func&& func) : func_(std::move(func)) {} 61 | ScopeGuard(const Func& func) : func_(func) {} 62 | ~ScopeGuard() { if (!commit_) func_(); } 63 | ScopeGuard(ScopeGuard&& other) : ScopeGuardBase(std::move(other)), func_(other.func_) {} 64 | private: 65 | Func func_; 66 | }; 67 | 68 | template 69 | ScopeGuard MakeGuard(Func&& func) { 70 | return ScopeGuard(std::forward(func)); 71 | } 72 | 73 | int main() { 74 | Storage S; 75 | Index I; 76 | try { 77 | S.insert(42, SUCCESS); 78 | auto SG = MakeGuard([&] { S.undo(); }); 79 | I.insert(42, FAIL_THROW); 80 | SG.commit(); 81 | } catch (...) { 82 | } 83 | 84 | if (S.get() != I.get()) std::cout << "Inconsistent state: " << S.get() << " != " << I.get() << std::endl; 85 | else std::cout << "Database OK" << std::endl; 86 | } 87 | -------------------------------------------------------------------------------- /Chapter11/07a_scopeguard_lambda_cleanup.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | enum Outcome { SUCCESS, FAIL_RETURN, FAIL_THROW }; 4 | 5 | // Demo disk storage, does nothing useful but may throw exception. 6 | class Storage { 7 | public: 8 | Storage() : i_(0), finalized_(false) {} 9 | bool insert(int i, Outcome outcome) { 10 | if (outcome == FAIL_THROW) throw 0; 11 | if (outcome == FAIL_RETURN) return false; 12 | i1_ = i_; i_ = i; 13 | return true; 14 | } 15 | void undo() { 16 | i_ = i1_; 17 | } 18 | void finalize() { finalized_ = true; } 19 | bool finalized() const { return finalized_; } 20 | int get() const { return i_; } 21 | private: 22 | int i_; 23 | int i1_; 24 | bool finalized_; 25 | }; 26 | 27 | // Demo memory index, does nothing useful but may throw exception. 28 | class Index { 29 | public: 30 | Index() : i_(0) {} 31 | bool insert(int i, Outcome outcome) { 32 | if (outcome == FAIL_THROW) throw 0; 33 | if (outcome == FAIL_RETURN) return false; 34 | i1_ = i_; i_ = i; 35 | return true; 36 | } 37 | void undo() { 38 | i_ = i1_; 39 | } 40 | int get() const { return i_; } 41 | private: 42 | int i_; 43 | int i1_; 44 | }; 45 | 46 | class ScopeGuardBase { 47 | public: 48 | ScopeGuardBase() : commit_(false) {} 49 | void commit() const noexcept { commit_ = true; } 50 | 51 | protected: 52 | ScopeGuardBase(ScopeGuardBase&& other) : commit_(other.commit_) { other.commit(); } 53 | ~ScopeGuardBase() {} 54 | mutable bool commit_; 55 | 56 | private: 57 | ScopeGuardBase& operator=(const ScopeGuardBase&) = delete; 58 | }; 59 | 60 | template 61 | class ScopeGuard : public ScopeGuardBase { 62 | public: 63 | ScopeGuard(Func&& func) : func_(func) {} 64 | ScopeGuard(const Func& func) : func_(func) {} 65 | ~ScopeGuard() { if (!commit_) func_(); } 66 | ScopeGuard(ScopeGuard&& other) : ScopeGuardBase(std::move(other)), func_(other.func_) {} 67 | private: 68 | Func func_; 69 | }; 70 | 71 | template 72 | ScopeGuard MakeGuard(Func&& func) { 73 | return ScopeGuard(std::forward(func)); 74 | } 75 | 76 | int main() { 77 | Storage S; 78 | Index I; 79 | try { 80 | S.insert(42, SUCCESS); 81 | auto SF = MakeGuard([&] { S.finalize(); }); 82 | auto SG = MakeGuard([&] { S.undo(); }); 83 | I.insert(42, FAIL_THROW); 84 | SG.commit(); 85 | } catch (...) { 86 | } 87 | 88 | if (S.get() != I.get()) std::cout << "Inconsistent state: " << S.get() << " != " << I.get() << std::endl; 89 | else if (!S.finalized()) std::cout << "Not finalized" << std::endl; 90 | else std::cout << "Database OK" << std::endl; 91 | } 92 | -------------------------------------------------------------------------------- /Chapter11/08_scopeguard_exception.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | enum Outcome { SUCCESS, FAIL_RETURN, FAIL_THROW }; 4 | 5 | // Demo disk storage, does nothing useful but may throw exception. 6 | class Storage { 7 | public: 8 | Storage() : i_(0), finalized_(false) {} 9 | bool insert(int i, Outcome outcome) { 10 | if (outcome == FAIL_THROW) throw 0; 11 | if (outcome == FAIL_RETURN) return false; 12 | i1_ = i_; i_ = i; 13 | return true; 14 | } 15 | void undo() { 16 | throw 0; 17 | i_ = i1_; 18 | } 19 | void finalize() { finalized_ = true; } 20 | bool finalized() const { return finalized_; } 21 | int get() const { return i_; } 22 | private: 23 | int i_; 24 | int i1_; 25 | bool finalized_; 26 | }; 27 | 28 | // Demo memory index, does nothing useful but may throw exception. 29 | class Index { 30 | public: 31 | Index() : i_(0) {} 32 | bool insert(int i, Outcome outcome) { 33 | if (outcome == FAIL_THROW) throw 0; 34 | if (outcome == FAIL_RETURN) return false; 35 | i1_ = i_; i_ = i; 36 | return true; 37 | } 38 | void undo() { 39 | i_ = i1_; 40 | } 41 | int get() const { return i_; } 42 | private: 43 | int i_; 44 | int i1_; 45 | }; 46 | 47 | class ScopeGuardBase { 48 | public: 49 | ScopeGuardBase() : commit_(false) {} 50 | void commit() const noexcept { commit_ = true; } 51 | 52 | protected: 53 | ScopeGuardBase(ScopeGuardBase&& other) : commit_(other.commit_) { other.commit(); } 54 | ~ScopeGuardBase() {} 55 | mutable bool commit_; 56 | 57 | private: 58 | ScopeGuardBase& operator=(const ScopeGuardBase&) = delete; 59 | }; 60 | 61 | template 62 | class ScopeGuard : public ScopeGuardBase { 63 | public: 64 | ScopeGuard(Func&& func) : func_(func) {} 65 | ScopeGuard(const Func& func) : func_(func) {} 66 | ~ScopeGuard() { if (!commit_) func_(); } 67 | ScopeGuard(ScopeGuard&& other) : ScopeGuardBase(std::move(other)), func_(other.func_) {} 68 | private: 69 | Func func_; 70 | }; 71 | 72 | template 73 | ScopeGuard MakeGuard(Func&& func) { 74 | return ScopeGuard(std::forward(func)); 75 | } 76 | 77 | int main() { 78 | Storage S; 79 | Index I; 80 | try { 81 | S.insert(42, SUCCESS); 82 | auto SF = MakeGuard([&] { S.finalize(); }); 83 | auto SG = MakeGuard([&] { S.undo(); }); 84 | I.insert(42, FAIL_THROW); 85 | SG.commit(); 86 | } catch (...) { 87 | } 88 | 89 | if (S.get() != I.get()) std::cout << "Inconsistent state: " << S.get() << " != " << I.get() << std::endl; 90 | else if (!S.finalized()) std::cout << "Not finalized" << std::endl; 91 | else std::cout << "Database OK" << std::endl; 92 | } 93 | -------------------------------------------------------------------------------- /Chapter11/09_scopeguard_shielded.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | enum Outcome { SUCCESS, FAIL_RETURN, FAIL_THROW }; 4 | 5 | // Demo disk storage, does nothing useful but may throw exception. 6 | class Storage { 7 | public: 8 | Storage() : i_(0), finalized_(false) {} 9 | bool insert(int i, Outcome outcome) { 10 | if (outcome == FAIL_THROW) throw 0; 11 | if (outcome == FAIL_RETURN) return false; 12 | i1_ = i_; i_ = i; 13 | return true; 14 | } 15 | void undo() { 16 | throw 0; 17 | i_ = i1_; 18 | } 19 | void finalize() { finalized_ = true; } 20 | bool finalized() const { return finalized_; } 21 | int get() const { return i_; } 22 | private: 23 | int i_; 24 | int i1_; 25 | bool finalized_; 26 | }; 27 | 28 | // Demo memory index, does nothing useful but may throw exception. 29 | class Index { 30 | public: 31 | Index() : i_(0) {} 32 | bool insert(int i, Outcome outcome) { 33 | if (outcome == FAIL_THROW) throw 0; 34 | if (outcome == FAIL_RETURN) return false; 35 | i1_ = i_; i_ = i; 36 | return true; 37 | } 38 | void undo() { 39 | i_ = i1_; 40 | } 41 | int get() const { return i_; } 42 | private: 43 | int i_; 44 | int i1_; 45 | }; 46 | 47 | class ScopeGuardBase { 48 | public: 49 | ScopeGuardBase() : commit_(false) {} 50 | void commit() const noexcept { commit_ = true; } 51 | 52 | protected: 53 | ScopeGuardBase(ScopeGuardBase&& other) : commit_(other.commit_) { other.commit(); } 54 | ~ScopeGuardBase() {} 55 | mutable bool commit_; 56 | 57 | private: 58 | ScopeGuardBase& operator=(const ScopeGuardBase&) = delete; 59 | }; 60 | 61 | template 62 | class ScopeGuard : public ScopeGuardBase { 63 | public: 64 | ScopeGuard(Func&& func) : func_(func) {} 65 | ScopeGuard(const Func& func) : func_(func) {} 66 | ~ScopeGuard() { 67 | if (!commit_) try { func_(); } catch (...) {} 68 | } 69 | ScopeGuard(ScopeGuard&& other) : ScopeGuardBase(std::move(other)), func_(other.func_) {} 70 | private: 71 | Func func_; 72 | }; 73 | 74 | template 75 | ScopeGuard MakeGuard(Func&& func) { 76 | return ScopeGuard(std::forward(func)); 77 | } 78 | 79 | int main() { 80 | Storage S; 81 | Index I; 82 | try { 83 | S.insert(42, SUCCESS); 84 | auto SF = MakeGuard([&] { S.finalize(); }); 85 | auto SG = MakeGuard([&] { S.undo(); }); 86 | I.insert(42, FAIL_THROW); 87 | SG.commit(); 88 | } catch (...) { 89 | } 90 | 91 | if (S.get() != I.get()) std::cout << "Inconsistent state: " << S.get() << " != " << I.get() << std::endl; 92 | else if (!S.finalized()) std::cout << "Not finalized" << std::endl; 93 | else std::cout << "Database OK" << std::endl; 94 | } 95 | -------------------------------------------------------------------------------- /Chapter11/10_scopeguard_lambda_cpp17.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | enum Outcome { SUCCESS, FAIL_RETURN, FAIL_THROW }; 4 | 5 | // Demo disk storage, does nothing useful but may throw exception. 6 | class Storage { 7 | public: 8 | Storage() : i_(0), finalized_(false) {} 9 | bool insert(int i, Outcome outcome) { 10 | if (outcome == FAIL_THROW) throw 0; 11 | if (outcome == FAIL_RETURN) return false; 12 | i1_ = i_; i_ = i; 13 | return true; 14 | } 15 | void undo() { 16 | i_ = i1_; 17 | } 18 | void finalize() { finalized_ = true; } 19 | bool finalized() const { return finalized_; } 20 | int get() const { return i_; } 21 | private: 22 | int i_; 23 | int i1_; 24 | bool finalized_; 25 | }; 26 | 27 | // Demo memory index, does nothing useful but may throw exception. 28 | class Index { 29 | public: 30 | Index() : i_(0) {} 31 | bool insert(int i, Outcome outcome) { 32 | if (outcome == FAIL_THROW) throw 0; 33 | if (outcome == FAIL_RETURN) return false; 34 | i1_ = i_; i_ = i; 35 | return true; 36 | } 37 | void undo() { 38 | i_ = i1_; 39 | } 40 | int get() const { return i_; } 41 | private: 42 | int i_; 43 | int i1_; 44 | }; 45 | 46 | class ScopeGuardBase { 47 | public: 48 | ScopeGuardBase() : commit_(false) {} 49 | void commit() const noexcept { commit_ = true; } 50 | 51 | protected: 52 | ScopeGuardBase(ScopeGuardBase&& other) : commit_(other.commit_) { other.commit(); } 53 | ~ScopeGuardBase() {} 54 | mutable bool commit_; 55 | 56 | private: 57 | ScopeGuardBase& operator=(const ScopeGuardBase&) = delete; 58 | }; 59 | 60 | template 61 | class ScopeGuard : public ScopeGuardBase { 62 | public: 63 | ScopeGuard(Func&& func) : func_(func) {} 64 | ScopeGuard(const Func& func) : func_(func) {} 65 | ~ScopeGuard() { if (!commit_) func_(); } 66 | ScopeGuard(ScopeGuard&& other) : ScopeGuardBase(std::move(other)), func_(other.func_) {} 67 | private: 68 | Func func_; 69 | }; 70 | 71 | int main() { 72 | Storage S; 73 | Index I; 74 | try { 75 | S.insert(42, SUCCESS); 76 | auto SF = ScopeGuard([&] { S.finalize(); }); 77 | auto SG = ScopeGuard([&] { S.undo(); }); 78 | I.insert(42, FAIL_THROW); 79 | SG.commit(); 80 | } catch (...) { 81 | } 82 | 83 | if (S.get() != I.get()) std::cout << "Inconsistent state: " << S.get() << " != " << I.get() << std::endl; 84 | else if (!S.finalized()) std::cout << "Not finalized" << std::endl; 85 | else std::cout << "Database OK" << std::endl; 86 | } 87 | -------------------------------------------------------------------------------- /Chapter11/13_scopeguard_te.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | enum Outcome { SUCCESS, FAIL_RETURN, FAIL_THROW }; 5 | 6 | // Demo disk storage, does nothing useful but may throw exception. 7 | class Storage { 8 | public: 9 | Storage() : i_(0) {} 10 | bool insert(int i, Outcome outcome) { 11 | if (outcome == FAIL_THROW) throw 0; 12 | if (outcome == FAIL_RETURN) return false; 13 | i1_ = i_; i_ = i; 14 | return true; 15 | } 16 | void undo() { 17 | i_ = i1_; 18 | } 19 | int get() const { return i_; } 20 | private: 21 | int i_; 22 | int i1_; 23 | }; 24 | 25 | // Demo memory index, does nothing useful but may throw exception. 26 | class Index { 27 | public: 28 | Index() : i_(0) {} 29 | bool insert(int i, Outcome outcome) { 30 | if (outcome == FAIL_THROW) throw 0; 31 | if (outcome == FAIL_RETURN) return false; 32 | i1_ = i_; i_ = i; 33 | return true; 34 | } 35 | void undo() { 36 | i_ = i1_; 37 | } 38 | int get() const { return i_; } 39 | private: 40 | int i_; 41 | int i1_; 42 | }; 43 | 44 | class ScopeGuard { 45 | public: 46 | template ScopeGuard(Func&& func) : commit_(false), func_(func) {} 47 | template ScopeGuard(const Func& func) : commit_(false), func_(func) {} 48 | ~ScopeGuard() { if (!commit_) func_(); } 49 | void commit() const noexcept { commit_ = true; } 50 | ScopeGuard(ScopeGuard&& other) : commit_(other.commit_), func_(other.func_) { other.commit(); } 51 | private: 52 | mutable bool commit_; 53 | std::function func_; 54 | ScopeGuard& operator=(const ScopeGuard&) = delete; 55 | }; 56 | 57 | int main() { 58 | Storage S; 59 | Index I; 60 | try { 61 | S.insert(42, SUCCESS); 62 | ScopeGuard SG([&] { S.undo(); }); 63 | I.insert(42, FAIL_THROW); 64 | SG.commit(); 65 | } catch (...) { 66 | } 67 | 68 | if (S.get() != I.get()) std::cout << "Inconsistent state: " << S.get() << " != " << I.get() << std::endl; 69 | else std::cout << "Database OK" << std::endl; 70 | } 71 | -------------------------------------------------------------------------------- /Chapter12/equal_friend_factory_crtp.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template class B { 4 | public: 5 | friend bool operator!=(const D& lhs, const D& rhs) { return !(lhs == rhs); } 6 | }; 7 | 8 | template class C : public B> { 9 | T x_; 10 | public: 11 | C(T x) : x_(x) {} 12 | friend bool operator==(const C& lhs, const C& rhs) { return lhs.x_ == rhs.x_; } 13 | friend std::ostream& operator<<(std::ostream& out, const C& c) { 14 | out << c.x_; 15 | return out; 16 | } 17 | }; 18 | 19 | int main() { 20 | C c1(5), c2(7); 21 | std::cout << (c1 == c2) << (c1 != c2) << std::endl; 22 | std::cout << (c1 == 5) << (c1 != 5) << std::endl; 23 | std::cout << (7 == c2) << (7 != c2) << std::endl; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /Chapter12/friend_factory.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template class C { 4 | T x_; 5 | public: 6 | C(T x) : x_(x) {} 7 | friend std::ostream& operator<<(std::ostream& out, const C& c) { 8 | out << c.x_; 9 | return out; 10 | } 11 | friend C increase(C c, T dx) { return C(c.x_ + dx); } 12 | }; 13 | 14 | namespace ND { 15 | template class D { 16 | T x_; 17 | public: 18 | D(T x) : x_(x) {} 19 | friend std::ostream& operator<<(std::ostream& out, const D& d) { 20 | out << d.x_; 21 | return out; 22 | } 23 | friend D increase(D d, T dx) { return D(d.x_ + dx); } 24 | }; 25 | } 26 | 27 | int main() { 28 | C c1(5); 29 | std::cout << c1 << " " << increase(c1, 1) << std::endl; 30 | ND::D d1(5); 31 | std::cout << d1 << " " << increase(d1, 2) << std::endl; 32 | } 33 | 34 | -------------------------------------------------------------------------------- /Chapter12/friend_nontemplate.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class C { 4 | int x_; 5 | public: 6 | C(int x) : x_(x) {} 7 | friend std::ostream& operator<<(std::ostream& out, const C& c); 8 | friend C increase(C c, int dx); 9 | }; 10 | std::ostream& operator<<(std::ostream& out, const C& c) { 11 | out << c.x_; 12 | return out; 13 | } 14 | C increase(C c, int dx) { return C(c.x_ + dx); } 15 | 16 | class D { 17 | int x_; 18 | public: 19 | D(int x) : x_(x) {} 20 | friend std::ostream& operator<<(std::ostream& out, const D& d) { 21 | out << d.x_; 22 | return out; 23 | } 24 | friend D increase(D c, int dx) { return D(c.x_ + dx); } 25 | }; 26 | 27 | int main() { 28 | C c1(5); 29 | std::cout << c1 << " " << increase(c1, 1) << std::endl; 30 | D d1(5); 31 | std::cout << d1 << " " << increase(d1, 1) << std::endl; 32 | } 33 | -------------------------------------------------------------------------------- /Chapter12/friend_template.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template class C { 4 | T x_; 5 | public: 6 | C(T x) : x_(x) {} 7 | template friend std::ostream& operator<<(std::ostream& out, const C& c); 8 | }; 9 | template std::ostream& operator<<(std::ostream& out, const C& c) { 10 | out << c.x_; 11 | return out; 12 | } 13 | 14 | template class D { 15 | T x_; 16 | public: 17 | D(T x) : x_(x) {} 18 | template friend std::ostream& operator<<(std::ostream& out, const D& d) { 19 | out << d.x_; 20 | return out; 21 | } 22 | }; 23 | 24 | int main() { 25 | C c1(5); 26 | std::cout << c1 << std::endl; 27 | D d1(5); 28 | std::cout << d1 << std::endl; 29 | } 30 | -------------------------------------------------------------------------------- /Chapter12/plus_friend.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class C { 4 | int x_; 5 | public: 6 | C(int x) : x_(x) {} 7 | friend C operator+(const C& lhs, const C& rhs); 8 | friend std::ostream& operator<<(std::ostream& out, const C& c) { 9 | out << c.x_; 10 | return out; 11 | } 12 | }; 13 | C operator+(const C& lhs, const C& rhs) { return C(lhs.x_ + rhs.x_); } 14 | 15 | int main() { 16 | C c1(5), c2(7); 17 | std::cout << (c1 + c2) << std::endl; 18 | std::cout << (c1 + 3) << std::endl; 19 | std::cout << (3 + c1) << std::endl; 20 | } 21 | -------------------------------------------------------------------------------- /Chapter12/plus_friend1.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class C { 4 | int x_; 5 | public: 6 | C(int x) : x_(x) {} 7 | friend C operator+(const C& lhs, const C& rhs) { return C(lhs.x_ + rhs.x_); } 8 | friend std::ostream& operator<<(std::ostream& out, const C& c) { 9 | out << c.x_; 10 | return out; 11 | } 12 | }; 13 | 14 | int main() { 15 | C c1(5), c2(7); 16 | std::cout << (c1 + c2) << std::endl; 17 | std::cout << (c1 + 3) << std::endl; 18 | std::cout << (3 + c1) << std::endl; 19 | } 20 | -------------------------------------------------------------------------------- /Chapter12/plus_friend1_template.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template class C { 4 | T x_; 5 | public: 6 | C(T x) : x_(x) {} 7 | template friend C operator+(const C& lhs, const C& rhs) { return C(lhs.x_ + rhs.x_); } 8 | friend std::ostream& operator<<(std::ostream& out, const C& c) { 9 | out << c.x_; 10 | return out; 11 | } 12 | }; 13 | 14 | int main() { 15 | C c1(5), c2(7); 16 | std::cout << (c1 + c2) << std::endl; 17 | //std::cout << (c1 + 3) << std::endl; 18 | //std::cout << (3 + c1) << std::endl; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /Chapter12/plus_friend_factory.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template class C { 4 | T x_; 5 | public: 6 | C(T x) : x_(x) {} 7 | friend C operator+(const C& lhs, const C& rhs) { return C(lhs.x_ + rhs.x_); } 8 | friend std::ostream& operator<<(std::ostream& out, const C& c) { 9 | out << c.x_; 10 | return out; 11 | } 12 | }; 13 | 14 | int main() { 15 | C c1(5), c2(7); 16 | std::cout << (c1 + c2) << std::endl; 17 | std::cout << (c1 + 3) << std::endl; 18 | std::cout << (3 + c1) << std::endl; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /Chapter12/plus_friend_factory_crtp.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template class B { 4 | public: 5 | friend D operator+(const D& lhs, const D& rhs) { D res(lhs); res += rhs; return res; } 6 | friend std::ostream& operator<<(std::ostream& out, const D& d) { 7 | d.print(out); 8 | return out; 9 | } 10 | }; 11 | 12 | template class C : public B> { 13 | T x_; 14 | public: 15 | C(T x) : x_(x) {} 16 | C operator+=(const C& incr) { x_ += incr.x_; return *this; } 17 | void print(std::ostream& out) const { 18 | out << x_; 19 | } 20 | }; 21 | 22 | int main() { 23 | C c1(5), c2(7); 24 | std::cout << (c1 + c2) << std::endl; 25 | std::cout << (c1 + 3) << std::endl; 26 | std::cout << (3 + c1) << std::endl; 27 | } 28 | 29 | -------------------------------------------------------------------------------- /Chapter12/plus_friend_factory_ns.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace NS { 4 | template class C { 5 | T x_; 6 | public: 7 | C(T x) : x_(x) {} 8 | friend C operator+(const C& lhs, const C& rhs) { return C(lhs.x_ + rhs.x_); } 9 | friend std::ostream& operator<<(std::ostream& out, const C& c) { 10 | out << c.x_; 11 | return out; 12 | } 13 | }; 14 | } 15 | 16 | int main() { 17 | NS::C c1(5), c2(7); 18 | std::cout << (c1 + c2) << std::endl; 19 | std::cout << (c1 + 3) << std::endl; 20 | std::cout << (3 + c1) << std::endl; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /Chapter12/plus_friend_template.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template class C { 4 | T x_; 5 | public: 6 | C(T x) : x_(x) {} 7 | template friend C operator+(const C& lhs, const C& rhs); 8 | friend std::ostream& operator<<(std::ostream& out, const C& c) { 9 | out << c.x_; 10 | return out; 11 | } 12 | }; 13 | template C operator+(const C& lhs, const C& rhs) { return C(lhs.x_ + rhs.x_); } 14 | 15 | int main() { 16 | C c1(5), c2(7); 17 | std::cout << (c1 + c2) << std::endl; 18 | //std::cout << (c1 + 3) << std::endl; 19 | //std::cout << (3 + c1) << std::endl; 20 | } 21 | -------------------------------------------------------------------------------- /Chapter12/plus_member.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class C { 4 | int x_; 5 | public: 6 | C(int x) : x_(x) {} 7 | C operator+(const C& rhs) const { return C(x_ + rhs.x_); } 8 | friend std::ostream& operator<<(std::ostream& out, const C& c) { 9 | out << c.x_; 10 | return out; 11 | } 12 | }; 13 | 14 | int main() { 15 | C c1(5), c2(7); 16 | std::cout << (c1 + c2) << std::endl; 17 | std::cout << (c1 + 3) << std::endl; 18 | //std::cout << (3 + c1) << std::endl; 19 | } 20 | -------------------------------------------------------------------------------- /Chapter13/ctor_dtor_dynamic_type.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class A { 5 | public: 6 | A() { std::cout << "A::A(): " << typeid(*this).name() << std::endl; } 7 | virtual ~A() { std::cout << "A::~A(): " << typeid(*this).name() << std::endl; } 8 | }; 9 | 10 | class B : public A { 11 | public: 12 | B() { std::cout << "B::B(): " << typeid(*this).name() << std::endl; } 13 | ~B() { std::cout << "B::~B(): " << typeid(*this).name() << std::endl; } 14 | }; 15 | 16 | class C : public B { 17 | public: 18 | C() { std::cout << "C::C(): " << typeid(*this).name() << std::endl; } 19 | ~C() { std::cout << "C::~C(): " << typeid(*this).name() << std::endl; } 20 | }; 21 | 22 | int main() { 23 | C c; 24 | } 25 | -------------------------------------------------------------------------------- /Chapter13/ctor_dtor_static_type.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class A { 5 | public: 6 | A() { std::cout << "A::A(): " << typeid(*this).name() << std::endl; } 7 | ~A() { std::cout << "A::~A(): " << typeid(*this).name() << std::endl; } 8 | }; 9 | 10 | class B : public A { 11 | public: 12 | B() { std::cout << "B::B(): " << typeid(*this).name() << std::endl; } 13 | ~B() { std::cout << "B::~B(): " << typeid(*this).name() << std::endl; } 14 | }; 15 | 16 | class C : public B { 17 | public: 18 | C() { std::cout << "C::C(): " << typeid(*this).name() << std::endl; } 19 | ~C() { std::cout << "C::~C(): " << typeid(*this).name() << std::endl; } 20 | }; 21 | 22 | int main() { 23 | C c; 24 | } 25 | -------------------------------------------------------------------------------- /Chapter13/ctor_dtor_virtual_type.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class A { 5 | public: 6 | A() { whoami(); } 7 | virtual ~A() { whoami(); } 8 | virtual void whoami() const { std::cout << "A::whoami" << std::endl; } 9 | }; 10 | 11 | class B : public A { 12 | public: 13 | B() { whoami(); } 14 | ~B() { whoami(); } 15 | void whoami() const { std::cout << "B::whoami" << std::endl; } 16 | }; 17 | 18 | class C : public B { 19 | public: 20 | C() { whoami(); } 21 | ~C() { whoami(); } 22 | void whoami() const { std::cout << "C::whoami" << std::endl; } 23 | }; 24 | 25 | int main() { 26 | C* c; 27 | c.whoami(); 28 | } 29 | -------------------------------------------------------------------------------- /Chapter13/poly_copy.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class Base { 5 | public: 6 | virtual Base* clone() const = 0; 7 | }; 8 | 9 | class Derived : public Base { 10 | public: 11 | Derived* clone() const { return new Derived(*this); } 12 | }; 13 | 14 | int main() { 15 | Base* b0 = new Derived; 16 | Base* b1 = b0->clone(); 17 | } 18 | -------------------------------------------------------------------------------- /Chapter13/poly_copy_unique.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class Base { 5 | public: 6 | virtual std::unique_ptr clone() const = 0; 7 | }; 8 | 9 | class Derived : public Base { 10 | public: 11 | std::unique_ptr clone() const { return std::unique_ptr(new Derived(*this)); } 12 | }; 13 | 14 | int main() { 15 | std::unique_ptr b0(new Derived); 16 | std::unique_ptr b1 = b0->clone(); 17 | } 18 | 19 | -------------------------------------------------------------------------------- /Chapter13/poly_copy_unique_crtp.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template class Base { 5 | public: 6 | virtual std::unique_ptr clone() const = 0; 7 | std::unique_ptr clone1() const { 8 | return std::unique_ptr(new Derived(*static_cast(this))); 9 | } 10 | }; 11 | 12 | class Derived : public Base { 13 | public: 14 | std::unique_ptr clone() const { return std::unique_ptr(new Derived(*this)); } 15 | }; 16 | 17 | int main() { 18 | std::unique_ptr b0(new Derived); 19 | std::unique_ptr b1 = b0->clone1(); 20 | } 21 | 22 | -------------------------------------------------------------------------------- /Chapter13/poly_copy_unique_crtp1.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class Base { 5 | public: 6 | virtual Base* clone() const = 0; 7 | }; 8 | 9 | template class ClonerBase : public Base { 10 | public: 11 | Base* clone() const { 12 | return new Derived(*static_cast(this)); 13 | } 14 | }; 15 | 16 | class Derived : public ClonerBase { 17 | public: 18 | }; 19 | 20 | int main() { 21 | Base* b0(new Derived); 22 | Base* b1 = b0->clone(); 23 | } 24 | 25 | -------------------------------------------------------------------------------- /Chapter13/poly_copy_unique_crtp2.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class Base { 5 | public: 6 | virtual ~Base() {} 7 | Base* clone() const; 8 | }; 9 | 10 | class ClonerBase { 11 | public: 12 | virtual Base* clone() const = 0; 13 | }; 14 | 15 | Base* Base::clone() const { 16 | dynamic_cast(this)->clone(); 17 | }; 18 | 19 | template class Cloner : public ClonerBase { 20 | public: 21 | Base* clone() const { 22 | return new Derived(*static_cast(this)); 23 | } 24 | }; 25 | 26 | class Derived : public Base, public Cloner { 27 | public: 28 | }; 29 | 30 | int main() { 31 | Base* b0(new Derived); 32 | Base* b1 = b0->clone(); 33 | } 34 | 35 | -------------------------------------------------------------------------------- /Chapter13/type_registry.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class Building; 5 | typedef Building* (*BuildingFactory)(); 6 | 7 | int building_type_count = 0; 8 | 9 | std::vector> building_registry; 10 | void RegisterBuilding(BuildingFactory factory) { 11 | building_registry.push_back(std::make_pair(building_type_count++, factory)); 12 | } 13 | 14 | class Building { 15 | public: 16 | static Building* MakeBuilding(int building_type) { 17 | BuildingFactory factory = building_registry[building_type].second; 18 | return factory(); 19 | } 20 | }; 21 | 22 | class Farm : public Building { 23 | public: 24 | Farm() { std::cout << "new Farm" << std::endl; } 25 | static Building* MakeBuilding() { return new Farm; } 26 | static void Register() { 27 | ::RegisterBuilding(Farm::MakeBuilding); 28 | } 29 | }; 30 | 31 | class Forge : public Building { 32 | public: 33 | Forge() { std::cout << "new Forge" << std::endl; } 34 | static Building* MakeBuilding() { return new Forge; } 35 | static void Register() { 36 | ::RegisterBuilding(Forge::MakeBuilding); 37 | } 38 | }; 39 | 40 | int main() { 41 | Farm::Register(); 42 | Forge::Register(); 43 | Building* b0 = Building::MakeBuilding(0); 44 | Building* b1 = Building::MakeBuilding(1); 45 | } 46 | 47 | -------------------------------------------------------------------------------- /Chapter13/type_registry_unique.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | class Building; 6 | typedef Building* (*BuildingFactory)(); 7 | 8 | int building_type_count = 0; 9 | 10 | std::vector> building_registry; 11 | void RegisterBuilding(BuildingFactory factory) { 12 | building_registry.push_back(std::make_pair(building_type_count++, factory)); 13 | } 14 | 15 | class Building { 16 | public: 17 | static auto MakeBuilding(int building_type) { 18 | BuildingFactory factory = building_registry[building_type].second; 19 | return std::unique_ptr(factory()); 20 | } 21 | }; 22 | 23 | class Farm : public Building { 24 | public: 25 | Farm() { std::cout << "new Farm" << std::endl; } 26 | static Building* MakeBuilding() { return new Farm; } 27 | static void Register() { 28 | ::RegisterBuilding(Farm::MakeBuilding); 29 | } 30 | }; 31 | 32 | class Forge : public Building { 33 | public: 34 | Forge() { std::cout << "new Forge" << std::endl; } 35 | static Building* MakeBuilding() { return new Forge; } 36 | static void Register() { 37 | ::RegisterBuilding(Forge::MakeBuilding); 38 | } 39 | }; 40 | 41 | int main() { 42 | Farm::Register(); 43 | Forge::Register(); 44 | std::unique_ptr b0 = Building::MakeBuilding(0); 45 | std::unique_ptr b1 = Building::MakeBuilding(1); 46 | } 47 | 48 | -------------------------------------------------------------------------------- /Chapter13/unit_factory.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class Building; 5 | typedef Building* (*BuildingFactory)(); 6 | 7 | int building_type_count = 0; 8 | 9 | std::vector> building_registry; 10 | void RegisterBuilding(BuildingFactory factory) { 11 | building_registry.push_back(std::make_pair(building_type_count++, factory)); 12 | } 13 | 14 | class Unit {}; 15 | class Knight : public Unit { 16 | public: 17 | Knight() { std::cout << "new Knight" << std::endl; } 18 | }; 19 | class Mage : public Unit { 20 | public: 21 | Mage() { std::cout << "new Mage" << std::endl; } 22 | }; 23 | class Spider : public Unit { 24 | public: 25 | Spider() { std::cout << "new Spider" << std::endl; } 26 | }; 27 | 28 | class Building { 29 | public: 30 | static Building* MakeBuilding(int building_type) { 31 | BuildingFactory factory = building_registry[building_type].second; 32 | return factory(); 33 | } 34 | virtual Unit* MakeUnit() const = 0; 35 | }; 36 | 37 | class Castle : public Building { 38 | public: 39 | Castle() { std::cout << "new Castle" << std::endl; } 40 | static Building* MakeBuilding() { return new Castle; } 41 | static void Register() { 42 | ::RegisterBuilding(Castle::MakeBuilding); 43 | } 44 | Knight* MakeUnit() const { return new Knight; } 45 | }; 46 | 47 | class Tower : public Building { 48 | public: 49 | Tower() { std::cout << "new Tower" << std::endl; } 50 | static Building* MakeBuilding() { return new Tower; } 51 | static void Register() { 52 | ::RegisterBuilding(Tower::MakeBuilding); 53 | } 54 | Mage* MakeUnit() const { return new Mage; } 55 | }; 56 | 57 | class Mound : public Building { 58 | public: 59 | Mound() { std::cout << "new Mound" << std::endl; } 60 | static Building* MakeBuilding() { return new Mound; } 61 | static void Register() { 62 | ::RegisterBuilding(Mound::MakeBuilding); 63 | } 64 | Spider* MakeUnit() const { return new Spider; } 65 | }; 66 | 67 | int main() { 68 | Castle::Register(); 69 | Tower::Register(); 70 | Mound::Register(); 71 | Building* b0 = Building::MakeBuilding(0); 72 | Building* b1 = Building::MakeBuilding(1); 73 | Building* b2 = Building::MakeBuilding(2); 74 | Unit* u0 = b0->MakeUnit(); 75 | Unit* u1 = b1->MakeUnit(); 76 | Unit* u2 = b2->MakeUnit(); 77 | } 78 | 79 | -------------------------------------------------------------------------------- /Chapter15/singleton_eager.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "benchmark/benchmark.h" 4 | 5 | #define REPEAT2(x) x x 6 | #define REPEAT4(x) REPEAT2(x) REPEAT2(x) 7 | #define REPEAT8(x) REPEAT4(x) REPEAT4(x) 8 | #define REPEAT16(x) REPEAT8(x) REPEAT8(x) 9 | #define REPEAT32(x) REPEAT16(x) REPEAT16(x) 10 | #define REPEAT(x) REPEAT32(x) 11 | 12 | #include 13 | 14 | class Singleton { 15 | public: 16 | static Singleton& instance() { 17 | return instance_; 18 | } 19 | 20 | int& get() { return value_; } 21 | 22 | private: 23 | Singleton() : value_(0) { std::cout << "Singleton::Singleton()" << std::endl; } 24 | ~Singleton() { std::cout << "Singleton::~Singleton()" << std::endl; } 25 | Singleton(const Singleton&) = delete; 26 | Singleton& operator=(const Singleton&) = delete; 27 | 28 | private: 29 | static Singleton instance_; 30 | int value_; 31 | }; 32 | Singleton Singleton::instance_; 33 | 34 | void BM_singleton(benchmark::State& state) { 35 | //Singleton S; // Does not compile - cannot create another one 36 | Singleton& S = Singleton::instance(); 37 | for (auto _ : state) { 38 | REPEAT(benchmark::DoNotOptimize(++S.get());) 39 | } 40 | state.SetItemsProcessed(32*state.iterations()); 41 | } 42 | 43 | void BM_singletons(benchmark::State& state) { 44 | for (auto _ : state) { 45 | REPEAT(benchmark::DoNotOptimize(++Singleton::instance().get());) 46 | } 47 | state.SetItemsProcessed(32*state.iterations()); 48 | } 49 | 50 | BENCHMARK(BM_singleton)->ThreadRange(1, 64); 51 | BENCHMARK(BM_singletons)->ThreadRange(1, 64); 52 | 53 | BENCHMARK_MAIN(); 54 | -------------------------------------------------------------------------------- /Chapter15/singleton_lazy_leaky.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "benchmark/benchmark.h" 4 | 5 | #define REPEAT2(x) x x 6 | #define REPEAT4(x) REPEAT2(x) REPEAT2(x) 7 | #define REPEAT8(x) REPEAT4(x) REPEAT4(x) 8 | #define REPEAT16(x) REPEAT8(x) REPEAT8(x) 9 | #define REPEAT32(x) REPEAT16(x) REPEAT16(x) 10 | #define REPEAT(x) REPEAT32(x) 11 | 12 | #include 13 | 14 | class Singleton { 15 | public: 16 | static Singleton& instance() { 17 | static Singleton* inst = new Singleton; 18 | return *inst; 19 | } 20 | 21 | int& get() { return value_; } 22 | 23 | private: 24 | Singleton() : value_(0) { std::cout << "Singleton::Singleton()" << std::endl; } 25 | ~Singleton() { std::cout << "Singleton::~Singleton()" << std::endl; } 26 | Singleton(const Singleton&) = delete; 27 | Singleton& operator=(const Singleton&) = delete; 28 | 29 | private: 30 | int value_; 31 | }; 32 | 33 | void BM_singleton(benchmark::State& state) { 34 | //Singleton S; // Does not compile - cannot create another one 35 | Singleton& S = Singleton::instance(); 36 | for (auto _ : state) { 37 | REPEAT(benchmark::DoNotOptimize(++S.get());) 38 | } 39 | state.SetItemsProcessed(32*state.iterations()); 40 | } 41 | 42 | void BM_singletons(benchmark::State& state) { 43 | for (auto _ : state) { 44 | REPEAT(benchmark::DoNotOptimize(++Singleton::instance().get());) 45 | } 46 | state.SetItemsProcessed(32*state.iterations()); 47 | } 48 | 49 | BENCHMARK(BM_singleton)->ThreadRange(1, 64); 50 | BENCHMARK(BM_singletons)->ThreadRange(1, 64); 51 | 52 | BENCHMARK_MAIN(); 53 | -------------------------------------------------------------------------------- /Chapter15/singleton_meyers.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "benchmark/benchmark.h" 4 | 5 | #define REPEAT2(x) x x 6 | #define REPEAT4(x) REPEAT2(x) REPEAT2(x) 7 | #define REPEAT8(x) REPEAT4(x) REPEAT4(x) 8 | #define REPEAT16(x) REPEAT8(x) REPEAT8(x) 9 | #define REPEAT32(x) REPEAT16(x) REPEAT16(x) 10 | #define REPEAT(x) REPEAT32(x) 11 | 12 | #include 13 | 14 | class Singleton { 15 | public: 16 | static Singleton& instance() { 17 | static Singleton inst; 18 | return inst; 19 | } 20 | 21 | int& get() { return value_; } 22 | 23 | private: 24 | Singleton() : value_(0) { std::cout << "Singleton::Singleton()" << std::endl; } 25 | Singleton(const Singleton&) = delete; 26 | Singleton& operator=(const Singleton&) = delete; 27 | ~Singleton() { std::cout << "Singleton::~Singleton()" << std::endl; } 28 | 29 | private: 30 | int value_; 31 | }; 32 | 33 | void BM_singleton(benchmark::State& state) { 34 | //Singleton S; // Does not compile - cannot create another one 35 | Singleton& S = Singleton::instance(); 36 | for (auto _ : state) { 37 | REPEAT(benchmark::DoNotOptimize(++S.get());) 38 | } 39 | state.SetItemsProcessed(32*state.iterations()); 40 | } 41 | 42 | void BM_singletons(benchmark::State& state) { 43 | for (auto _ : state) { 44 | REPEAT(benchmark::DoNotOptimize(++Singleton::instance().get());) 45 | } 46 | state.SetItemsProcessed(32*state.iterations()); 47 | } 48 | 49 | BENCHMARK(BM_singleton)->ThreadRange(1, 64); 50 | BENCHMARK(BM_singletons)->ThreadRange(1, 64); 51 | 52 | BENCHMARK_MAIN(); 53 | -------------------------------------------------------------------------------- /Chapter15/singleton_meyers_pimpl.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "benchmark/benchmark.h" 4 | 5 | #define REPEAT2(x) x x 6 | #define REPEAT4(x) REPEAT2(x) REPEAT2(x) 7 | #define REPEAT8(x) REPEAT4(x) REPEAT4(x) 8 | #define REPEAT16(x) REPEAT8(x) REPEAT8(x) 9 | #define REPEAT32(x) REPEAT16(x) REPEAT16(x) 10 | #define REPEAT(x) REPEAT32(x) 11 | 12 | #include 13 | 14 | struct SingletonImpl; 15 | class Singleton { 16 | public: 17 | int& get(); 18 | 19 | private: 20 | static SingletonImpl& impl(); 21 | }; 22 | 23 | struct SingletonImpl { 24 | SingletonImpl() : value_(0) {} 25 | int value_; 26 | }; 27 | 28 | int& Singleton::get() { return impl().value_; } 29 | 30 | SingletonImpl& Singleton::impl() { 31 | static SingletonImpl inst; 32 | return inst; 33 | } 34 | 35 | void BM_singleton(benchmark::State& state) { 36 | //Singleton S; // Does not compile - cannot create another one 37 | Singleton S; 38 | for (auto _ : state) { 39 | REPEAT(benchmark::DoNotOptimize(++S.get());) 40 | } 41 | state.SetItemsProcessed(32*state.iterations()); 42 | } 43 | 44 | void BM_singletons(benchmark::State& state) { 45 | for (auto _ : state) { 46 | REPEAT(benchmark::DoNotOptimize(++Singleton().get());) 47 | } 48 | state.SetItemsProcessed(32*state.iterations()); 49 | } 50 | 51 | BENCHMARK(BM_singleton)->ThreadRange(1, 64); 52 | BENCHMARK(BM_singletons)->ThreadRange(1, 64); 53 | 54 | BENCHMARK_MAIN(); 55 | -------------------------------------------------------------------------------- /Chapter15/singleton_meyers_pimpl1.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "benchmark/benchmark.h" 4 | 5 | #define REPEAT2(x) x x 6 | #define REPEAT4(x) REPEAT2(x) REPEAT2(x) 7 | #define REPEAT8(x) REPEAT4(x) REPEAT4(x) 8 | #define REPEAT16(x) REPEAT8(x) REPEAT8(x) 9 | #define REPEAT32(x) REPEAT16(x) REPEAT16(x) 10 | #define REPEAT(x) REPEAT32(x) 11 | 12 | #include 13 | 14 | struct SingletonImpl; 15 | class Singleton { 16 | public: 17 | Singleton(); 18 | int& get(); 19 | 20 | private: 21 | static SingletonImpl& impl(); 22 | SingletonImpl& impl_; 23 | }; 24 | 25 | struct SingletonImpl { 26 | SingletonImpl() : value_(0) {} 27 | int value_; 28 | }; 29 | 30 | Singleton::Singleton() : impl_(impl()) {} 31 | 32 | int& Singleton::get() { return impl_.value_; } 33 | 34 | SingletonImpl& Singleton::impl() { 35 | static SingletonImpl inst; 36 | return inst; 37 | } 38 | 39 | void BM_singleton(benchmark::State& state) { 40 | //Singleton S; // Does not compile - cannot create another one 41 | Singleton S; 42 | for (auto _ : state) { 43 | REPEAT(benchmark::DoNotOptimize(++S.get());) 44 | } 45 | state.SetItemsProcessed(32*state.iterations()); 46 | } 47 | 48 | void BM_singletons(benchmark::State& state) { 49 | for (auto _ : state) { 50 | REPEAT(benchmark::DoNotOptimize(++Singleton().get());) 51 | } 52 | state.SetItemsProcessed(32*state.iterations()); 53 | } 54 | 55 | BENCHMARK(BM_singleton)->ThreadRange(1, 64); 56 | BENCHMARK(BM_singletons)->ThreadRange(1, 64); 57 | 58 | BENCHMARK_MAIN(); 59 | -------------------------------------------------------------------------------- /Chapter15/singleton_noaccess.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "benchmark/benchmark.h" 4 | 5 | #define REPEAT2(x) x x 6 | #define REPEAT4(x) REPEAT2(x) REPEAT2(x) 7 | #define REPEAT8(x) REPEAT4(x) REPEAT4(x) 8 | #define REPEAT16(x) REPEAT8(x) REPEAT8(x) 9 | #define REPEAT32(x) REPEAT16(x) REPEAT16(x) 10 | #define REPEAT(x) REPEAT32(x) 11 | 12 | #include 13 | 14 | class Singleton { 15 | public: 16 | int& get() { return value_; } 17 | 18 | private: 19 | Singleton() : value_(0) { std::cout << "Singleton::Singleton()" << std::endl; } 20 | Singleton(const Singleton&) = delete; 21 | Singleton& operator=(const Singleton&) = delete; 22 | ~Singleton() { std::cout << "Singleton::~Singleton()" << std::endl; } 23 | friend Singleton& SingletonInstance(); 24 | 25 | private: 26 | int value_; 27 | }; 28 | 29 | inline Singleton& SingletonInstance() { 30 | static Singleton inst; 31 | return inst; 32 | } 33 | 34 | void BM_singleton(benchmark::State& state) { 35 | for (auto _ : state) { 36 | REPEAT(benchmark::DoNotOptimize(++SingletonInstance().get());) 37 | } 38 | state.SetItemsProcessed(32*state.iterations()); 39 | } 40 | 41 | BENCHMARK(BM_singleton)->ThreadRange(1, 64); 42 | 43 | BENCHMARK_MAIN(); 44 | -------------------------------------------------------------------------------- /Chapter15/singleton_static.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "benchmark/benchmark.h" 4 | 5 | #define REPEAT2(x) x x 6 | #define REPEAT4(x) REPEAT2(x) REPEAT2(x) 7 | #define REPEAT8(x) REPEAT4(x) REPEAT4(x) 8 | #define REPEAT16(x) REPEAT8(x) REPEAT8(x) 9 | #define REPEAT32(x) REPEAT16(x) REPEAT16(x) 10 | #define REPEAT(x) REPEAT32(x) 11 | 12 | #include 13 | 14 | class Singleton { 15 | public: 16 | Singleton() {} 17 | int& get() { return value_; } 18 | 19 | private: 20 | Singleton(const Singleton&) = delete; 21 | Singleton& operator=(const Singleton&) = delete; 22 | 23 | private: 24 | static int value_; 25 | }; 26 | int Singleton::value_ = 0; 27 | 28 | void BM_singleton(benchmark::State& state) { 29 | Singleton S; 30 | for (auto _ : state) { 31 | REPEAT(benchmark::DoNotOptimize(++S.get());) 32 | } 33 | state.SetItemsProcessed(32*state.iterations()); 34 | } 35 | 36 | void BM_singletons(benchmark::State& state) { 37 | for (auto _ : state) { 38 | REPEAT(benchmark::DoNotOptimize(++Singleton().get());) 39 | } 40 | state.SetItemsProcessed(32*state.iterations()); 41 | } 42 | 43 | BENCHMARK(BM_singleton)->ThreadRange(1, 64); 44 | BENCHMARK(BM_singletons)->ThreadRange(1, 64); 45 | 46 | BENCHMARK_MAIN(); 47 | -------------------------------------------------------------------------------- /Chapter15/singleton_static1.C: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "benchmark/benchmark.h" 4 | 5 | #define REPEAT2(x) x x 6 | #define REPEAT4(x) REPEAT2(x) REPEAT2(x) 7 | #define REPEAT8(x) REPEAT4(x) REPEAT4(x) 8 | #define REPEAT16(x) REPEAT8(x) REPEAT8(x) 9 | #define REPEAT32(x) REPEAT16(x) REPEAT16(x) 10 | #define REPEAT(x) REPEAT32(x) 11 | 12 | #include 13 | 14 | class Singleton { 15 | public: 16 | static int& get() { return value_; } 17 | 18 | private: 19 | Singleton() = delete; 20 | Singleton(const Singleton&) = delete; 21 | Singleton& operator=(const Singleton&) = delete; 22 | 23 | private: 24 | static int value_; 25 | }; 26 | int Singleton::value_ = 0; 27 | 28 | void BM_singleton(benchmark::State& state) { 29 | for (auto _ : state) { 30 | REPEAT(benchmark::DoNotOptimize(++Singleton::get());) 31 | } 32 | state.SetItemsProcessed(32*state.iterations()); 33 | } 34 | 35 | BENCHMARK(BM_singleton)->ThreadRange(1, 64); 36 | 37 | BENCHMARK_MAIN(); 38 | 39 | -------------------------------------------------------------------------------- /Chapter16/01_scoped_ptr.C: -------------------------------------------------------------------------------- 1 | // Basic smart pointer with automatic deletion. 2 | #include 3 | #include 4 | 5 | template 6 | class SmartPtr { 7 | public: 8 | explicit SmartPtr(T* p = nullptr) 9 | : p_(p) {} 10 | ~SmartPtr() { 11 | delete p_; 12 | } 13 | void release() { p_ = NULL; } 14 | T* operator->() { return p_; } 15 | const T* operator->() const { return p_; } 16 | T& operator*() { return *p_; } 17 | const T& operator*() const { return *p_; } 18 | private: 19 | T* p_; 20 | SmartPtr(const SmartPtr&) = delete; 21 | SmartPtr& operator=(const SmartPtr&) = delete; 22 | }; 23 | 24 | int main() { 25 | SmartPtr p(new int(42)); 26 | std::cout << *p << std::endl; 27 | } 28 | -------------------------------------------------------------------------------- /Chapter16/02a_scoped_ptr_bug.C: -------------------------------------------------------------------------------- 1 | // Version 02 with a dangling reference bug. 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | struct DeleteByOperator { 8 | void operator()(T* p) const { 9 | delete p; 10 | } 11 | }; 12 | 13 | template 14 | struct DeleteByFree { 15 | void operator()(T* p) const { 16 | p->~T(); 17 | free(p); 18 | } 19 | }; 20 | 21 | template 22 | struct DeleteDestructorOnly { 23 | void operator()(T* p) const { 24 | p->~T(); 25 | } 26 | }; 27 | 28 | class SmallHeap { 29 | public: 30 | SmallHeap() {} 31 | ~SmallHeap() {} 32 | void* allocate(size_t s) { 33 | assert(s <= size_); 34 | return mem_; 35 | } 36 | void deallocate(void* p) { 37 | assert(p == mem_); 38 | } 39 | private: 40 | static constexpr size_t size_ = 1024; 41 | char mem_[size_]; 42 | SmallHeap(const SmallHeap&) = delete; 43 | SmallHeap& operator=(const SmallHeap&) = delete; 44 | }; 45 | void* operator new(size_t s, SmallHeap* h) { return h->allocate(s); } 46 | 47 | template 48 | struct DeleteSmallHeap { 49 | ~DeleteSmallHeap() 50 | { 51 | std::cout << "Dtor " << this << std::endl; 52 | } 53 | explicit DeleteSmallHeap(SmallHeap& heap) 54 | : heap_(heap) 55 | { 56 | std::cout << "Ctor " << this << std::endl; 57 | } 58 | void operator()(T* p) const { 59 | p->~T(); 60 | heap_.deallocate(p); 61 | } 62 | private: 63 | SmallHeap& heap_; 64 | DeleteSmallHeap(const DeleteSmallHeap&) = delete; 65 | DeleteSmallHeap& operator=(const DeleteSmallHeap&) = delete; 66 | }; 67 | 68 | template > 69 | class SmartPtr { 70 | public: 71 | explicit SmartPtr(T* p = nullptr, 72 | const DeletionPolicy& deletion_policy = DeletionPolicy() 73 | ) : p_(p), 74 | deletion_policy_(deletion_policy) 75 | {} 76 | ~SmartPtr() { 77 | deletion_policy_(p_); 78 | } 79 | void release() { p_ = NULL; } 80 | T* operator->() { return p_; } 81 | const T* operator->() const { return p_; } 82 | T& operator*() { return *p_; } 83 | const T& operator*() const { return *p_; } 84 | private: 85 | T* p_; 86 | const DeletionPolicy& deletion_policy_; 87 | SmartPtr(const SmartPtr&) = delete; 88 | SmartPtr& operator=(const SmartPtr&) = delete; 89 | }; 90 | 91 | int main() { 92 | { 93 | SmartPtr p(new int(42)); 94 | std::cout << *p << std::endl; 95 | } 96 | 97 | { 98 | SmallHeap h; 99 | SmartPtr> p{new(&h) int(42), DeleteSmallHeap(h)}; 100 | std::cout << *p << std::endl; 101 | } 102 | } 103 | 104 | -------------------------------------------------------------------------------- /Chapter16/02b_scoped_ptr.C: -------------------------------------------------------------------------------- 1 | // Version 02 for C++17. 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | struct DeleteByOperator { 8 | void operator()(T* p) const { 9 | delete p; 10 | } 11 | }; 12 | 13 | template 14 | struct DeleteByFree { 15 | void operator()(T* p) const { 16 | p->~T(); 17 | free(p); 18 | } 19 | }; 20 | 21 | template 22 | struct DeleteDestructorOnly { 23 | void operator()(T* p) const { 24 | p->~T(); 25 | } 26 | }; 27 | 28 | class SmallHeap { 29 | public: 30 | SmallHeap() {} 31 | ~SmallHeap() {} 32 | void* allocate(size_t s) { 33 | assert(s <= size_); 34 | return mem_; 35 | } 36 | void deallocate(void* p) { 37 | assert(p == mem_); 38 | } 39 | private: 40 | static constexpr size_t size_ = 1024; 41 | char mem_[size_]; 42 | SmallHeap(const SmallHeap&) = delete; 43 | SmallHeap& operator=(const SmallHeap&) = delete; 44 | }; 45 | void* operator new(size_t s, SmallHeap* h) { return h->allocate(s); } 46 | 47 | template 48 | struct DeleteSmallHeap { 49 | explicit DeleteSmallHeap(SmallHeap& heap) 50 | : heap_(heap) {} 51 | void operator()(T* p) const { 52 | p->~T(); 53 | heap_.deallocate(p); 54 | } 55 | private: 56 | SmallHeap& heap_; 57 | }; 58 | 59 | template > 60 | class SmartPtr { 61 | public: 62 | explicit SmartPtr(T* p = nullptr, 63 | const DeletionPolicy& deletion_policy = DeletionPolicy() 64 | ) : p_(p), 65 | deletion_policy_(deletion_policy) 66 | {} 67 | ~SmartPtr() { 68 | deletion_policy_(p_); 69 | } 70 | void release() { p_ = NULL; } 71 | T* operator->() { return p_; } 72 | const T* operator->() const { return p_; } 73 | T& operator*() { return *p_; } 74 | const T& operator*() const { return *p_; } 75 | private: 76 | T* p_; 77 | DeletionPolicy deletion_policy_; 78 | SmartPtr(const SmartPtr&) = delete; 79 | SmartPtr& operator=(const SmartPtr&) = delete; 80 | }; 81 | 82 | int main() { 83 | { 84 | SmartPtr p(new int(42)); 85 | std::cout << *p << std::endl; 86 | } 87 | 88 | { 89 | SmallHeap h; 90 | SmartPtr p{new(&h) int(42), DeleteSmallHeap(h)}; 91 | std::cout << *p << std::endl; 92 | } 93 | } 94 | 95 | -------------------------------------------------------------------------------- /Chapter16/02c_scoped_ptr.C: -------------------------------------------------------------------------------- 1 | // Version 02 with non-template deletion policy. 2 | #include 3 | #include 4 | #include 5 | 6 | struct DeleteByOperator { 7 | template 8 | void operator()(T* p) const { 9 | delete p; 10 | } 11 | }; 12 | 13 | struct DeleteByFree { 14 | template 15 | void operator()(T* p) const { 16 | p->~T(); 17 | free(p); 18 | } 19 | }; 20 | 21 | struct DeleteDestructorOnly { 22 | template 23 | void operator()(T* p) const { 24 | p->~T(); 25 | } 26 | }; 27 | 28 | class SmallHeap { 29 | public: 30 | SmallHeap() {} 31 | ~SmallHeap() {} 32 | void* allocate(size_t s) { 33 | assert(s <= size_); 34 | return mem_; 35 | } 36 | void deallocate(void* p) { 37 | assert(p == mem_); 38 | } 39 | private: 40 | static constexpr size_t size_ = 1024; 41 | char mem_[size_]; 42 | SmallHeap(const SmallHeap&) = delete; 43 | SmallHeap& operator=(const SmallHeap&) = delete; 44 | }; 45 | void* operator new(size_t s, SmallHeap* h) { return h->allocate(s); } 46 | 47 | struct DeleteSmallHeap { 48 | explicit DeleteSmallHeap(SmallHeap& heap) 49 | : heap_(heap) {} 50 | template 51 | void operator()(T* p) const { 52 | p->~T(); 53 | heap_.deallocate(p); 54 | } 55 | private: 56 | SmallHeap& heap_; 57 | }; 58 | 59 | template 60 | class SmartPtr { 61 | public: 62 | explicit SmartPtr(T* p = nullptr, 63 | const DeletionPolicy& deletion_policy = DeletionPolicy() 64 | ) : p_(p), 65 | deletion_policy_(deletion_policy) 66 | {} 67 | ~SmartPtr() { 68 | deletion_policy_(p_); 69 | } 70 | void release() { p_ = NULL; } 71 | T* operator->() { return p_; } 72 | const T* operator->() const { return p_; } 73 | T& operator*() { return *p_; } 74 | const T& operator*() const { return *p_; } 75 | private: 76 | T* p_; 77 | DeletionPolicy deletion_policy_; 78 | SmartPtr(const SmartPtr&) = delete; 79 | SmartPtr& operator=(const SmartPtr&) = delete; 80 | }; 81 | 82 | int main() { 83 | { 84 | SmartPtr p(new int(42)); 85 | std::cout << *p << std::endl; 86 | } 87 | 88 | { 89 | SmallHeap h; 90 | SmartPtr p{new(&h) int(42), DeleteSmallHeap(h)}; 91 | std::cout << *p << std::endl; 92 | } 93 | } 94 | 95 | -------------------------------------------------------------------------------- /Chapter16/02d_scoped_ptr.C: -------------------------------------------------------------------------------- 1 | // Version 02 with template and non-template deletion policies. 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | struct DeleteByOperator { 8 | void operator()(T* p) const { 9 | delete p; 10 | } 11 | }; 12 | 13 | struct DeleteByFree { 14 | template 15 | void operator()(T* p) const { 16 | p->~T(); 17 | free(p); 18 | } 19 | }; 20 | 21 | struct DeleteDestructorOnly { 22 | template 23 | void operator()(T* p) const { 24 | p->~T(); 25 | } 26 | }; 27 | 28 | class SmallHeap { 29 | public: 30 | SmallHeap() {} 31 | ~SmallHeap() {} 32 | void* allocate(size_t s) { 33 | assert(s <= size_); 34 | return mem_; 35 | } 36 | void deallocate(void* p) { 37 | assert(p == mem_); 38 | } 39 | private: 40 | static constexpr size_t size_ = 1024; 41 | char mem_[size_]; 42 | SmallHeap(const SmallHeap&) = delete; 43 | SmallHeap& operator=(const SmallHeap&) = delete; 44 | }; 45 | void* operator new(size_t s, SmallHeap* h) { return h->allocate(s); } 46 | 47 | struct DeleteSmallHeap { 48 | explicit DeleteSmallHeap(SmallHeap& heap) 49 | : heap_(heap) {} 50 | template 51 | void operator()(T* p) const { 52 | p->~T(); 53 | heap_.deallocate(p); 54 | } 55 | private: 56 | SmallHeap& heap_; 57 | }; 58 | 59 | template > 60 | class SmartPtr { 61 | public: 62 | explicit SmartPtr(T* p = nullptr, 63 | const DeletionPolicy& deletion_policy = DeletionPolicy() 64 | ) : p_(p), 65 | deletion_policy_(deletion_policy) 66 | {} 67 | ~SmartPtr() { 68 | deletion_policy_(p_); 69 | } 70 | void release() { p_ = NULL; } 71 | T* operator->() { return p_; } 72 | const T* operator->() const { return p_; } 73 | T& operator*() { return *p_; } 74 | const T& operator*() const { return *p_; } 75 | private: 76 | T* p_; 77 | DeletionPolicy deletion_policy_; 78 | SmartPtr(const SmartPtr&) = delete; 79 | SmartPtr& operator=(const SmartPtr&) = delete; 80 | }; 81 | 82 | int main() { 83 | { 84 | SmartPtr p(new int(42)); 85 | std::cout << *p << std::endl; 86 | } 87 | 88 | { 89 | SmallHeap h; 90 | SmartPtr p{new(&h) int(42), DeleteSmallHeap(h)}; 91 | std::cout << *p << std::endl; 92 | } 93 | } 94 | 95 | -------------------------------------------------------------------------------- /Chapter16/02e_scoped_ptr.C: -------------------------------------------------------------------------------- 1 | // Version 02 with template template deletion policy. 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | struct DeleteByOperator { 8 | void operator()(T* p) const { 9 | delete p; 10 | } 11 | }; 12 | 13 | template 14 | struct DeleteByFree { 15 | void operator()(T* p) const { 16 | p->~T(); 17 | free(p); 18 | } 19 | }; 20 | 21 | template 22 | struct DeleteDestructorOnly { 23 | void operator()(T* p) const { 24 | p->~T(); 25 | } 26 | }; 27 | 28 | class SmallHeap { 29 | public: 30 | SmallHeap() {} 31 | ~SmallHeap() {} 32 | void* allocate(size_t s) { 33 | assert(s <= size_); 34 | return mem_; 35 | } 36 | void deallocate(void* p) { 37 | assert(p == mem_); 38 | } 39 | private: 40 | static constexpr size_t size_ = 1024; 41 | char mem_[size_]; 42 | SmallHeap(const SmallHeap&) = delete; 43 | SmallHeap& operator=(const SmallHeap&) = delete; 44 | }; 45 | void* operator new(size_t s, SmallHeap* h) { return h->allocate(s); } 46 | 47 | template 48 | struct DeleteSmallHeap { 49 | explicit DeleteSmallHeap(SmallHeap& heap) 50 | : heap_(heap) {} 51 | void operator()(T* p) const { 52 | p->~T(); 53 | heap_.deallocate(p); 54 | } 55 | private: 56 | SmallHeap& heap_; 57 | }; 58 | 59 | template class DeletionPolicy = DeleteByOperator> 60 | class SmartPtr { 61 | public: 62 | explicit SmartPtr(T* p = nullptr, 63 | const DeletionPolicy& deletion_policy = DeletionPolicy() 64 | ) : p_(p), 65 | deletion_policy_(deletion_policy) 66 | {} 67 | ~SmartPtr() { 68 | deletion_policy_(p_); 69 | } 70 | void release() { p_ = NULL; } 71 | T* operator->() { return p_; } 72 | const T* operator->() const { return p_; } 73 | T& operator*() { return *p_; } 74 | const T& operator*() const { return *p_; } 75 | private: 76 | T* p_; 77 | DeletionPolicy deletion_policy_; 78 | SmartPtr(const SmartPtr&) = delete; 79 | SmartPtr& operator=(const SmartPtr&) = delete; 80 | }; 81 | 82 | int main() { 83 | { 84 | SmartPtr p(new int(42)); 85 | std::cout << *p << std::endl; 86 | } 87 | 88 | { 89 | SmallHeap h; 90 | SmartPtr p{new(&h) int(42), DeleteSmallHeap(h)}; 91 | std::cout << *p << std::endl; 92 | } 93 | } 94 | 95 | -------------------------------------------------------------------------------- /Chapter16/02f_scoped_ptr.C: -------------------------------------------------------------------------------- 1 | // Version 02e for C++17. 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | struct DeleteByOperator { 8 | void operator()(T* p) const { 9 | delete p; 10 | } 11 | }; 12 | 13 | template 14 | struct DeleteByFree { 15 | void operator()(T* p) const { 16 | p->~T(); 17 | free(p); 18 | } 19 | }; 20 | 21 | template 22 | struct DeleteDestructorOnly { 23 | void operator()(T* p) const { 24 | p->~T(); 25 | } 26 | }; 27 | 28 | class SmallHeap { 29 | public: 30 | SmallHeap() {} 31 | ~SmallHeap() {} 32 | void* allocate(size_t s) { 33 | assert(s <= size_); 34 | return mem_; 35 | } 36 | void deallocate(void* p) { 37 | assert(p == mem_); 38 | } 39 | private: 40 | static constexpr size_t size_ = 1024; 41 | char mem_[size_]; 42 | SmallHeap(const SmallHeap&) = delete; 43 | SmallHeap& operator=(const SmallHeap&) = delete; 44 | }; 45 | void* operator new(size_t s, SmallHeap* h) { return h->allocate(s); } 46 | 47 | template 48 | struct DeleteSmallHeap { 49 | explicit DeleteSmallHeap(SmallHeap& heap) 50 | : heap_(heap) {} 51 | void operator()(T* p) const { 52 | p->~T(); 53 | heap_.deallocate(p); 54 | } 55 | private: 56 | SmallHeap& heap_; 57 | }; 58 | 59 | template class DeletionPolicy = DeleteByOperator> 60 | class SmartPtr { 61 | public: 62 | explicit SmartPtr(T* p = nullptr, 63 | const DeletionPolicy& deletion_policy = DeletionPolicy() 64 | ) : p_(p), 65 | deletion_policy_(deletion_policy) 66 | {} 67 | ~SmartPtr() { 68 | deletion_policy_(p_); 69 | } 70 | void release() { p_ = NULL; } 71 | T* operator->() { return p_; } 72 | const T* operator->() const { return p_; } 73 | T& operator*() { return *p_; } 74 | const T& operator*() const { return *p_; } 75 | private: 76 | T* p_; 77 | DeletionPolicy deletion_policy_; 78 | SmartPtr(const SmartPtr&) = delete; 79 | SmartPtr& operator=(const SmartPtr&) = delete; 80 | }; 81 | 82 | int main() { 83 | { 84 | SmartPtr p(new int(42)); 85 | std::cout << *p << std::endl; 86 | } 87 | 88 | { 89 | SmartPtr p(new int(42), DeleteByOperator()); 90 | std::cout << *p << std::endl; 91 | } 92 | 93 | { 94 | SmallHeap h; 95 | SmartPtr p{new(&h) int(42), DeleteSmallHeap(h)}; 96 | std::cout << *p << std::endl; 97 | } 98 | } 99 | 100 | -------------------------------------------------------------------------------- /Chapter16/03a_scoped_ptr.C: -------------------------------------------------------------------------------- 1 | // Version 03 for C++17. 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | struct DeleteByOperator { 9 | void operator()(T* p) const { 10 | delete p; 11 | } 12 | }; 13 | 14 | template 15 | struct DeleteByFree { 16 | void operator()(T* p) const { 17 | p->~T(); 18 | free(p); 19 | } 20 | }; 21 | 22 | template 23 | struct DeleteDestructorOnly { 24 | void operator()(T* p) const { 25 | p->~T(); 26 | } 27 | }; 28 | 29 | class SmallHeap { 30 | public: 31 | SmallHeap() {} 32 | ~SmallHeap() {} 33 | void* allocate(size_t s) { 34 | assert(s <= size_); 35 | return mem_; 36 | } 37 | void deallocate(void* p) { 38 | assert(p == mem_); 39 | } 40 | private: 41 | static constexpr size_t size_ = 1024; 42 | char mem_[size_]; 43 | SmallHeap(const SmallHeap&) = delete; 44 | SmallHeap& operator=(const SmallHeap&) = delete; 45 | }; 46 | void* operator new(size_t s, SmallHeap* h) { return h->allocate(s); } 47 | 48 | template 49 | struct DeleteSmallHeap { 50 | explicit DeleteSmallHeap(SmallHeap& heap) 51 | : heap_(&heap) {} 52 | void operator()(T* p) const { 53 | p->~T(); 54 | heap_->deallocate(p); 55 | } 56 | DeleteSmallHeap(DeleteSmallHeap&& other) 57 | : heap_(other.heap_) 58 | { 59 | other.heap_ = nullptr; 60 | } 61 | private: 62 | SmallHeap* heap_; 63 | DeleteSmallHeap(const DeleteSmallHeap&) = delete; 64 | DeleteSmallHeap& operator=(const DeleteSmallHeap&) = delete; 65 | }; 66 | 67 | template > 68 | class SmartPtr : private DeletionPolicy { 69 | public: 70 | explicit SmartPtr(T* p = nullptr, 71 | DeletionPolicy&& deletion_policy = DeletionPolicy() 72 | ) : DeletionPolicy(std::move(deletion_policy)), 73 | p_(p) 74 | {} 75 | ~SmartPtr() { 76 | DeletionPolicy::operator()(p_); 77 | } 78 | void release() { p_ = NULL; } 79 | T* operator->() { return p_; } 80 | const T* operator->() const { return p_; } 81 | T& operator*() { return *p_; } 82 | const T& operator*() const { return *p_; } 83 | private: 84 | T* p_; 85 | SmartPtr(const SmartPtr&) = delete; 86 | SmartPtr& operator=(const SmartPtr&) = delete; 87 | }; 88 | 89 | int main() { 90 | { 91 | SmartPtr p(new int(42)); 92 | std::cout << *p << std::endl; 93 | } 94 | 95 | { 96 | SmallHeap h; 97 | SmartPtr p{new(&h) int(42), DeleteSmallHeap(h)}; 98 | std::cout << *p << std::endl; 99 | } 100 | } 101 | 102 | -------------------------------------------------------------------------------- /Chapter17/01_decorator.C: -------------------------------------------------------------------------------- 1 | // Basic decorator 2 | #include 3 | using std::cout; 4 | using std::endl; 5 | 6 | class Unit { 7 | public: 8 | Unit(double strength, double armor) : strength_(strength), armor_(armor) {} 9 | virtual bool hit(Unit& target) { return attack() > target.defense(); } 10 | virtual double attack() = 0; 11 | virtual double defense() = 0; 12 | protected: 13 | double strength_; 14 | double armor_; 15 | }; 16 | 17 | class Knight : public Unit { 18 | public: 19 | using Unit::Unit; 20 | double attack() { return strength_ + sword_bonus_; } 21 | double defense() { return armor_ + plate_bonus_; } 22 | protected: 23 | static constexpr double sword_bonus_ = 2; 24 | static constexpr double plate_bonus_ = 3; 25 | }; 26 | 27 | class Ogre : public Unit { 28 | public: 29 | using Unit::Unit; 30 | double attack() { return strength_ + club_penalty_; } 31 | double defense() { return armor_ + leather_penalty_; } 32 | protected: 33 | static constexpr double club_penalty_ = -1; 34 | static constexpr double leather_penalty_ = -1; 35 | }; 36 | 37 | class Troll : public Unit { 38 | public: 39 | using Unit::Unit; 40 | double attack() { return strength_ + mace_bonus_; } 41 | double defense() { return armor_ + hide_bonus_; } 42 | protected: 43 | static constexpr double mace_bonus_ = 3; 44 | static constexpr double hide_bonus_ = 8; 45 | }; 46 | 47 | class VeteranUnit : public Unit { 48 | public: 49 | VeteranUnit(Unit& unit, double strength_bonus, double armor_bonus) : Unit(strength_bonus, armor_bonus), unit_(unit) {} 50 | double attack() { return unit_.attack() + strength_; } 51 | double defense() { return unit_.defense() + armor_; } 52 | private: 53 | Unit& unit_; 54 | }; 55 | 56 | int main() { 57 | Knight k(10, 5); 58 | Ogre o(12, 2); 59 | cout << "Knight hits Ogre: " << k.hit(o) << endl; 60 | Troll t(14, 10); 61 | cout << "Knight hits Troll: " << k.hit(t) << endl; 62 | VeteranUnit vk(k, 7, 2); 63 | cout << "Veteran Knight hits Troll: " << vk.hit(t) << endl; 64 | VeteranUnit vo(o, 1, 9); 65 | cout << "Veteran Knight hits Veteran Ogre: " << vk.hit(vo) << endl; 66 | VeteranUnit vvo(vo, 1, 9); 67 | cout << "Veteran Knight hits Veteran2 Ogre: " << vk.hit(vvo) << endl; 68 | } 69 | -------------------------------------------------------------------------------- /Chapter17/01a_decorator.C: -------------------------------------------------------------------------------- 1 | // 01 with non-wrapped function 2 | #include 3 | using std::cout; 4 | using std::endl; 5 | 6 | // Basic decorator 7 | class Unit { 8 | public: 9 | Unit(double strength, double armor) : strength_(strength), armor_(armor) {} 10 | virtual bool hit(Unit& target) { return attack() > target.defense(); } 11 | virtual double attack() = 0; 12 | virtual double defense() = 0; 13 | protected: 14 | double strength_; 15 | double armor_; 16 | }; 17 | 18 | class Knight : public Unit { 19 | public: 20 | Knight(double strength, double armor) : Unit(strength, armor), charge_bonus_(0) {} 21 | double attack() { double res = strength_ + sword_bonus_ + charge_bonus_; charge_bonus_ = 0; return res; } 22 | double defense() { return armor_ + plate_bonus_; } 23 | void charge() { charge_bonus_ = 1; } 24 | protected: 25 | double charge_bonus_; 26 | static constexpr double sword_bonus_ = 2; 27 | static constexpr double plate_bonus_ = 3; 28 | }; 29 | 30 | class Ogre : public Unit { 31 | public: 32 | using Unit::Unit; 33 | double attack() { return strength_ + club_penalty_; } 34 | double defense() { return armor_ + leather_penalty_; } 35 | void Beserk() { strength_ += 5; armor_ -= 2; } 36 | protected: 37 | static constexpr double club_penalty_ = -1; 38 | static constexpr double leather_penalty_ = -1; 39 | }; 40 | 41 | class VeteranUnit : public Unit { 42 | public: 43 | VeteranUnit(Unit& unit, double strength_bonus, double armor_bonus) : Unit(strength_bonus, armor_bonus), unit_(unit) {} 44 | double attack() { return unit_.attack() + strength_; } 45 | double defense() { return unit_.defense() + armor_; } 46 | private: 47 | Unit& unit_; 48 | }; 49 | 50 | int main() { 51 | Knight k(10, 5); 52 | Ogre o(12, 2); 53 | k.charge(); 54 | cout << "Knight hits Ogre: " << k.hit(o) << endl; 55 | VeteranUnit vk(k, 7, 2); 56 | //vk.charge(); // Does not compile 57 | cout << "Veteran Knight hits Ogre: " << vk.hit(o) << endl; 58 | } 59 | -------------------------------------------------------------------------------- /Chapter17/02_decorator.C: -------------------------------------------------------------------------------- 1 | // CRTP decorator 2 | #include 3 | using std::cout; 4 | using std::endl; 5 | 6 | // Basic decorator 7 | class Unit { 8 | public: 9 | Unit(double strength, double armor) : strength_(strength), armor_(armor) {} 10 | virtual bool hit(Unit& target) { return attack() > target.defense(); } 11 | virtual double attack() = 0; 12 | virtual double defense() = 0; 13 | protected: 14 | double strength_; 15 | double armor_; 16 | }; 17 | 18 | class Knight : public Unit { 19 | public: 20 | Knight(double strength, double armor) : Unit(strength, armor), charge_bonus_(0) {} 21 | double attack() { double res = strength_ + sword_bonus_ + charge_bonus_; charge_bonus_ = 0; return res; } 22 | double defense() { return armor_ + plate_bonus_; } 23 | void charge() { charge_bonus_ = 1; } 24 | protected: 25 | double charge_bonus_; 26 | static constexpr double sword_bonus_ = 2; 27 | static constexpr double plate_bonus_ = 3; 28 | }; 29 | 30 | class Ogre : public Unit { 31 | public: 32 | using Unit::Unit; 33 | double attack() { return strength_ + club_penalty_; } 34 | double defense() { return armor_ + leather_penalty_; } 35 | protected: 36 | static constexpr double club_penalty_ = -1; 37 | static constexpr double leather_penalty_ = -1; 38 | }; 39 | 40 | class Troll : public Unit { 41 | public: 42 | using Unit::Unit; 43 | double attack() { return strength_ + mace_bonus_; } 44 | double defense() { return armor_ + hide_bonus_; } 45 | protected: 46 | static constexpr double mace_bonus_ = 3; 47 | static constexpr double hide_bonus_ = 8; 48 | }; 49 | 50 | template class VeteranUnit : public U { 51 | public: 52 | VeteranUnit(U&& unit, double strength_bonus, double armor_bonus) : U(unit), strength_bonus_(strength_bonus), armor_bonus_(armor_bonus) {} 53 | double attack() { return U::attack() + strength_bonus_; } 54 | double defense() { return U::defense() + armor_bonus_; } 55 | private: 56 | double strength_bonus_; 57 | double armor_bonus_; 58 | }; 59 | 60 | int main() { 61 | Knight k(10, 5); 62 | Ogre o(12, 2); 63 | k.charge(); 64 | cout << "Knight hits Ogre: " << k.hit(o) << endl; 65 | Troll t(14, 10); 66 | cout << "Knight hits Troll: " << k.hit(t) << endl; 67 | VeteranUnit vk(std::move(k), 7, 2); 68 | cout << "Veteran Knight hits Troll: " << vk.hit(t) << endl; 69 | VeteranUnit vo(std::move(o), 1, 9); 70 | cout << "Veteran Knight hits Veteran Ogre: " << vk.hit(vo) << endl; 71 | VeteranUnit> vvo(std::move(vo), 1, 9); 72 | cout << "Veteran Knight hits Veteran2 Ogre: " << vk.hit(vvo) << endl; 73 | vk.charge(); 74 | cout << "Veteran Knight hits Veteran2 Ogre: " << vk.hit(vvo) << endl; 75 | //VeteranUnit> vvk(vk, 7, 2); // Does not compile! 76 | } 77 | -------------------------------------------------------------------------------- /Chapter17/04a_decorator.C: -------------------------------------------------------------------------------- 1 | // Universal decorator 2 | #include 3 | #include 4 | using std::cout; 5 | using std::endl; 6 | 7 | template class DebugDecorator { 8 | public: 9 | DebugDecorator(const Callable& c, const char* s) : c_(c), s_(s) {} 10 | template auto operator()(Args&& ... args) const { 11 | cout << "Invoking " << s_ << endl; 12 | auto res = c_(std::forward(args) ...); 13 | cout << "Result: " << res << endl; 14 | return res; 15 | } 16 | 17 | private: 18 | const Callable& c_; 19 | const std::string s_; 20 | }; 21 | 22 | template 23 | auto decorate_debug(const Callable& c, const char* s) { 24 | return DebugDecorator(c, s); 25 | } 26 | 27 | struct R { 28 | int value() const { return rand(); } 29 | }; 30 | 31 | int g(int i, int j) { return i - j; } 32 | 33 | struct S { 34 | double operator()() const { return double(rand() + 1)/double(rand() + 1); } 35 | }; 36 | 37 | double x = 0; 38 | double& fx() { return x; } 39 | const double& cfx() { return x; } 40 | 41 | int main() { 42 | auto f1 = decorate_debug([](int i) { return i; }, "i->i"); 43 | f1(5); 44 | 45 | auto f2 = decorate_debug([](int i, int j) { return i + j; }, "i+j"); 46 | f2(5, 3); 47 | 48 | auto g1 = decorate_debug(g, "g()"); 49 | g1(5, 2); 50 | 51 | S s; 52 | auto s1 = decorate_debug(s, "rand/rand"); 53 | s1(); s1(); 54 | 55 | R r; 56 | auto f0 = decorate_debug([&]() { return r.value(); }, "rand"); 57 | f0(); f0(); 58 | 59 | auto fx1 = decorate_debug(fx, "fx()"); 60 | fx() = 5; cout << "x=" << x << endl; 61 | //fx1() = 6; cout << "x=" << x << endl; // Needs more work to preserve the & 62 | 63 | auto cfx1 = decorate_debug(cfx, "cfx()"); 64 | cfx1(); 65 | 66 | //auto incr = decorate_debug([](int& x) { ++x; }, "++x"); 67 | //int i = 0; 68 | //incr(i); // Does not compile - "void res" is invalid 69 | } 70 | -------------------------------------------------------------------------------- /Chapter17/04b_decorator.C: -------------------------------------------------------------------------------- 1 | // 04a with support for void 2 | #include 3 | #include 4 | using std::cout; 5 | using std::endl; 6 | 7 | template struct report { 8 | Res res; 9 | template 10 | report(const Callable& c, Args&& ... args) : 11 | res(c(std::forward(args) ...)) { 12 | cout << "Result: " << res << endl; 13 | } 14 | Res operator()() { return res; } 15 | }; 16 | template <> struct report { 17 | template 18 | report(const Callable& c, Args&& ... args) { 19 | c(std::forward(args) ...); 20 | cout << "Done" << endl; 21 | } 22 | void operator()() {} 23 | }; 24 | 25 | template class DebugDecorator { 26 | public: 27 | DebugDecorator(const Callable& c, const char* s) : c_(c), s_(s) {} 28 | template auto operator()(Args&& ... args) const { 29 | cout << "Invoking " << s_ << endl; 30 | using Callable_ref = Callable&; 31 | using res_t = typename std::result_of::type; 32 | report res(c_, std::forward(args) ...); 33 | return res(); 34 | } 35 | 36 | private: 37 | const Callable& c_; 38 | const std::string s_; 39 | }; 40 | 41 | template 42 | auto decorate_debug(const Callable& c, const char* s) { 43 | return DebugDecorator(c, s); 44 | } 45 | 46 | struct R { 47 | int value() const { return rand(); } 48 | }; 49 | 50 | int g(int i, int j) { return i - j; } 51 | 52 | struct S { 53 | double operator()() const { return double(rand() + 1)/double(rand() + 1); } 54 | }; 55 | 56 | double x = 0; 57 | double& fx() { return x; } 58 | const double& cfx() { return x; } 59 | 60 | int main() { 61 | auto f1 = decorate_debug([](int i) { return i; }, "i->i"); 62 | f1(5); 63 | 64 | auto f2 = decorate_debug([](int i, int j) { return i + j; }, "i+j"); 65 | f2(5, 3); 66 | 67 | auto g1 = decorate_debug(g, "g()"); 68 | g1(5, 2); 69 | 70 | S s; 71 | auto s1 = decorate_debug(s, "rand/rand"); 72 | s1(); s1(); 73 | 74 | R r; 75 | auto f0 = decorate_debug([&]() { return r.value(); }, "rand"); 76 | f0(); f0(); 77 | 78 | auto fx1 = decorate_debug(fx, "fx()"); 79 | fx() = 1; cout << "x=" << x << endl; 80 | //fx1() = 5; cout << "x=" << x << endl; // This is tricky but possible 81 | 82 | auto cfx1 = decorate_debug(cfx, "cfx()"); 83 | cfx1(); 84 | 85 | auto incr = decorate_debug([](int& x) { ++x; }, "++x"); 86 | int i = 0; 87 | incr(i); 88 | } 89 | -------------------------------------------------------------------------------- /Chapter17/04c_decorator.C: -------------------------------------------------------------------------------- 1 | // 04b with GCC extensions 2 | #include 3 | #include 4 | using std::cout; 5 | using std::endl; 6 | 7 | template struct report { 8 | Res res; 9 | template 10 | report(const Callable& c, Args&& ... args) : 11 | res(c(std::forward(args) ...)) { 12 | cout << "Result: " << res << endl; 13 | } 14 | Res operator()() { return res; } 15 | }; 16 | template <> struct report { 17 | template 18 | report(const Callable& c, Args&& ... args) { 19 | c(std::forward(args) ...); 20 | cout << "Done" << endl; 21 | } 22 | void operator()() {} 23 | }; 24 | 25 | template class DebugDecorator { 26 | public: 27 | DebugDecorator(const Callable& c, const char* s) : c_(c), s_(s) {} 28 | template auto operator()(Args&& ... args) const { 29 | cout << "Invoking " << s_ << " (" << __PRETTY_FUNCTION__ << ")" << endl; 30 | using Callable_ref = Callable&; 31 | using res_t = typename std::result_of::type; 32 | report res(c_, std::forward(args) ...); 33 | return res(); 34 | } 35 | 36 | private: 37 | const Callable& c_; 38 | const std::string s_; 39 | }; 40 | 41 | template 42 | auto decorate_debug(const Callable& c, const char* s) { 43 | return DebugDecorator(c, s); 44 | } 45 | 46 | struct R { 47 | int value() const { return rand(); } 48 | }; 49 | 50 | int g(int i, int j) { return i - j; } 51 | 52 | struct S { 53 | double operator()() const { return double(rand() + 1)/double(rand() + 1); } 54 | }; 55 | 56 | double x = 0; 57 | double& fx() { return x; } 58 | 59 | int main() { 60 | auto f1 = decorate_debug([](int i) { return i; }, "i->i"); 61 | f1(5); 62 | 63 | auto f2 = decorate_debug([](int i, int j) { return i + j; }, "i+j"); 64 | f2(5, 3); 65 | 66 | auto g1 = decorate_debug(g, "g()"); 67 | g1(5, 2); 68 | 69 | S s; 70 | auto s1 = decorate_debug(s, "rand/rand"); 71 | s1(); s1(); 72 | 73 | R r; 74 | auto f0 = decorate_debug([&]() { return r.value(); }, "rand"); 75 | f0(); f0(); 76 | 77 | auto fx1 = decorate_debug(fx, "fx()"); 78 | fx1(); 79 | 80 | auto incr = decorate_debug([](int& x) { ++x; }, "++x"); 81 | int i = 0; 82 | incr(i); 83 | } 84 | -------------------------------------------------------------------------------- /Chapter17/04d_decorator.C: -------------------------------------------------------------------------------- 1 | // 04b with composable decorators 2 | #include 3 | #include 4 | #include 5 | using std::cout; 6 | using std::endl; 7 | 8 | template struct report { 9 | Res res; 10 | template 11 | report(const Callable& c, Args&& ... args) : 12 | res(c(std::forward(args) ...)) { 13 | cout << "Result: " << res << endl; 14 | } 15 | Res operator()() { return res; } 16 | }; 17 | template <> struct report { 18 | template 19 | report(const Callable& c, Args&& ... args) { 20 | c(std::forward(args) ...); 21 | cout << "Done" << endl; 22 | } 23 | void operator()() {} 24 | }; 25 | 26 | template class DebugDecorator { 27 | public: 28 | DebugDecorator(const Callable& c, const char* s) : c_(c), s_(s) {} 29 | template auto operator()(Args&& ... args) const { 30 | cout << "Invoking " << s_ << endl; 31 | using res_t = typename std::result_of::type; 32 | report res(c_, std::forward(args) ...); 33 | return res(); 34 | } 35 | 36 | private: 37 | const Callable& c_; 38 | const std::string s_; 39 | }; 40 | 41 | template 42 | auto decorate_debug(const Callable& c, const char* s) { 43 | return DebugDecorator(c, s); 44 | } 45 | 46 | template class LockDecorator { 47 | public: 48 | LockDecorator(const Callable& c, std::mutex& m) : c_(c), m_(m) {} 49 | template auto operator()(Args&& ... args) const { 50 | std::lock_guard l(m_); 51 | return c_(std::forward(args) ...); 52 | } 53 | 54 | private: 55 | const Callable& c_; 56 | std::mutex& m_; 57 | }; 58 | 59 | template 60 | auto decorate_lock(const Callable& c, std::mutex& m) { 61 | return LockDecorator(c, m); 62 | } 63 | 64 | struct R { 65 | int value() const { return rand(); } 66 | }; 67 | 68 | int main() { 69 | std::mutex m; 70 | auto f1 = decorate_lock(decorate_debug([](int i) { return i; }, "i->i"), m); 71 | f1(5); 72 | auto f2 = decorate_debug(decorate_lock([](int i, int j) { return i + j; }, m), "i+j"); 73 | f2(5, 3); 74 | R r; 75 | auto f0 = decorate_lock([&]() { return r.value(); }, m); 76 | f0(); f0(); 77 | auto incr = decorate_debug([](int& x) { ++x; }, "++x"); 78 | int i = 0; 79 | incr(i); 80 | } 81 | -------------------------------------------------------------------------------- /Chapter17/05_locking_queue.C: -------------------------------------------------------------------------------- 1 | // Locking queue 2 | #include 3 | #include 4 | #include 5 | using std::cout; 6 | using std::endl; 7 | 8 | template class locking_queue { 9 | using mutex = std::mutex; 10 | using lock_guard = std::lock_guard; 11 | public: 12 | using value_type = typename std::queue::value_type; 13 | void push(const value_type& value) { 14 | lock_guard l(m_); 15 | q_.push(value); 16 | } 17 | void push(value_type&& value) { 18 | lock_guard l(m_); 19 | q_.push(value); 20 | } 21 | bool pop(value_type& value) { 22 | lock_guard l(m_); 23 | if (q_.empty()) return false; 24 | value = std::move(q_.front()); 25 | q_.pop(); 26 | return true; 27 | } 28 | 29 | private: 30 | std::queue q_; 31 | mutex m_; 32 | }; 33 | 34 | int main() { 35 | locking_queue q; 36 | q.push(1); 37 | q.push(2); 38 | q.push(3); 39 | int x = 0; 40 | cout << q.pop(x) << " " << x << endl; 41 | cout << q.pop(x) << " " << x << endl; 42 | cout << q.pop(x) << " " << x << endl; 43 | cout << q.pop(x) << " " << x << endl; 44 | } 45 | -------------------------------------------------------------------------------- /Chapter17/05a_locking_queue.C: -------------------------------------------------------------------------------- 1 | // 05 returning a pair 2 | #include 3 | #include 4 | #include 5 | #include 6 | using std::cout; 7 | using std::endl; 8 | 9 | template class locking_queue { 10 | using mutex = std::mutex; 11 | using lock_guard = std::lock_guard; 12 | public: 13 | using value_type = typename std::queue::value_type; 14 | using reference = typename std::queue::reference; 15 | void push(const value_type& value) { 16 | lock_guard l(m_); 17 | q_.push(value); 18 | } 19 | void push(value_type&& value) { 20 | lock_guard l(m_); 21 | q_.push(value); 22 | } 23 | std::pair pop() { 24 | lock_guard l(m_); 25 | if (q_.empty()) return { value_type(), false }; 26 | value_type value = std::move(q_.front()); 27 | q_.pop(); 28 | return { value, true }; 29 | } 30 | 31 | private: 32 | std::queue q_; 33 | mutex m_; 34 | }; 35 | 36 | int main() { 37 | locking_queue q; 38 | q.push(1); 39 | q.push(2); 40 | q.push(3); 41 | auto x = q.pop(); cout << x.second << " " << x.first << endl; 42 | x = q.pop(); cout << x.second << " " << x.first << endl; 43 | x = q.pop(); cout << x.second << " " << x.first << endl; 44 | x = q.pop(); cout << x.second << " " << x.first << endl; 45 | } 46 | -------------------------------------------------------------------------------- /Chapter17/06_adapter_curry.C: -------------------------------------------------------------------------------- 1 | // Currying function argument 2 | #include 3 | #include 4 | #include 5 | using std::cout; 6 | using std::endl; 7 | 8 | struct much_less { 9 | template bool operator()(T x, T y) { return x < y && std::abs(x - y) > tolerance*std::max(std::abs(x), std::abs(y)); } 10 | static constexpr double tolerance = 0.2; 11 | }; 12 | 13 | template void sort_much_less(RandomIt first, RandomIt last) { 14 | std::sort(first, last, much_less()); 15 | } 16 | 17 | int main() { 18 | const size_t N = 20; 19 | std::vector v(N); 20 | for (size_t i = 0; i < N; ++i) { 21 | v[i] = (N - i)*0.1; 22 | } 23 | sort_much_less(v.begin(), v.end()); 24 | for (auto x : v) { 25 | cout << x << " "; 26 | } 27 | cout << endl; 28 | } 29 | -------------------------------------------------------------------------------- /Chapter17/06a_adapter_curry.C: -------------------------------------------------------------------------------- 1 | // 06 with container adapter 2 | #include 3 | #include 4 | #include 5 | using std::cout; 6 | using std::endl; 7 | 8 | struct much_less { 9 | template bool operator()(T x, T y) { return x < y && std::abs(x - y) > tolerance*std::max(std::abs(x), std::abs(y)); } 10 | static constexpr double tolerance = 0.2; 11 | }; 12 | 13 | template void sort_much_less(Container& c) { 14 | std::sort(c.begin(), c.end(), much_less()); 15 | } 16 | 17 | int main() { 18 | const size_t N = 20; 19 | std::vector v(N); 20 | for (size_t i = 0; i < N; ++i) { 21 | v[i] = (N - i)*0.1; 22 | } 23 | sort_much_less(v); 24 | for (auto x : v) { 25 | cout << x << " "; 26 | } 27 | cout << endl; 28 | } 29 | -------------------------------------------------------------------------------- /Chapter17/06b_adapter_lambda.C: -------------------------------------------------------------------------------- 1 | // 06 using lambda 2 | #include 3 | #include 4 | #include 5 | using std::cout; 6 | using std::endl; 7 | 8 | struct much_less { 9 | template bool operator()(T x, T y) { return x < y && std::abs(x - y) > tolerance*std::max(std::abs(x), std::abs(y)); } 10 | static constexpr double tolerance = 0.2; 11 | }; 12 | 13 | auto sort_much_less = [](auto first, auto last) { return std::sort(first, last, much_less()); }; 14 | 15 | int main() { 16 | const size_t N = 20; 17 | std::vector v(N); 18 | for (size_t i = 0; i < N; ++i) { 19 | v[i] = (N - i)*0.1; 20 | } 21 | sort_much_less(v.begin(), v.end()); 22 | for (auto x : v) { 23 | cout << x << " "; 24 | } 25 | cout << endl; 26 | } 27 | -------------------------------------------------------------------------------- /Chapter17/06c_adapter_bind.C: -------------------------------------------------------------------------------- 1 | // 06 using std::bind 2 | #include 3 | #include 4 | #include 5 | #include 6 | using std::cout; 7 | using std::endl; 8 | using namespace std::placeholders; // For _1, _2 etc 9 | 10 | // std::bind example 11 | int f3(int i, int j, int k) { return i + j + k; } 12 | auto f2 = std::bind(f3, _1, _2, 42); 13 | 14 | struct much_less { 15 | template bool operator()(T x, T y) { return x < y && std::abs(x - y) > 0.2*std::max(std::abs(x), std::abs(y)); } 16 | }; 17 | 18 | template void sort_much_less(RandomIt first, RandomIt last) { 19 | auto f = std::bind(std::sort, _1, _2, much_less()); 20 | f(first, last, much_less()); 21 | } 22 | 23 | int main() { 24 | cout << f2(2, 6) << endl; 25 | 26 | const size_t N = 20; 27 | std::vector v(N); 28 | for (size_t i = 0; i < N; ++i) { 29 | v[i] = (N - i)*0.1; 30 | } 31 | sort_much_less(v.begin(), v.end()); 32 | for (auto x : v) { 33 | cout << x << " "; 34 | } 35 | cout << endl; 36 | } 37 | -------------------------------------------------------------------------------- /Chapter17/06c_adapter_lambda.C: -------------------------------------------------------------------------------- 1 | // 06a using lambda 2 | #include 3 | #include 4 | #include 5 | using std::cout; 6 | using std::endl; 7 | 8 | struct much_less { 9 | template bool operator()(T x, T y) { return x < y && std::abs(x - y) > tolerance*std::max(std::abs(x), std::abs(y)); } 10 | static constexpr double tolerance = 0.2; 11 | }; 12 | 13 | auto sort_much_less = [](auto& container) { return std::sort(container.begin(), container.end(), much_less()); }; 14 | 15 | int main() { 16 | const size_t N = 20; 17 | std::vector v(N); 18 | for (size_t i = 0; i < N; ++i) { 19 | v[i] = (N - i)*0.1; 20 | } 21 | sort_much_less(v); 22 | for (auto x : v) { 23 | cout << x << " "; 24 | } 25 | cout << endl; 26 | } 27 | -------------------------------------------------------------------------------- /Chapter17/06d_adapter_bind.C: -------------------------------------------------------------------------------- 1 | // 06 using std::bind 2 | #include 3 | #include 4 | #include 5 | #include 6 | using std::cout; 7 | using std::endl; 8 | using namespace std::placeholders; // For _1, _2 etc 9 | 10 | // std::bind example 11 | int f3(int i, int j, int k) { return i + j + k; } 12 | auto f2 = std::bind(f3, _1, _2, 42); 13 | auto f1 = std::bind(f3, 5, _1, 7); 14 | 15 | struct much_less { 16 | template bool operator()(T x, T y) { return x < y && std::abs(x - y) > tolerance*std::max(std::abs(x), std::abs(y)); } 17 | static constexpr double tolerance = 0.2; 18 | }; 19 | 20 | template void sort_much_less(RandomIt first, RandomIt last) { 21 | auto f = std::bind(std::sort, _1, _2, much_less()); 22 | f(first, last, much_less()); 23 | } 24 | 25 | int main() { 26 | cout << f2(2, 6) << endl; 27 | cout << f1(3) << endl; 28 | 29 | const size_t N = 20; 30 | std::vector v(N); 31 | for (size_t i = 0; i < N; ++i) { 32 | v[i] = (N - i)*0.1; 33 | } 34 | sort_much_less(v.begin(), v.end()); 35 | for (auto x : v) { 36 | cout << x << " "; 37 | } 38 | cout << endl; 39 | } 40 | -------------------------------------------------------------------------------- /Chapter17/07_template_template_adapter.C: -------------------------------------------------------------------------------- 1 | // Adapter for template template 2 | #include 3 | #include 4 | #include 5 | using std::cout; 6 | using std::endl; 7 | 8 | template class Buffer { 9 | public: 10 | explicit Buffer(size_t N) : N_(N), buffer_(new T[N_]) {} 11 | ~Buffer() { delete [] buffer_; } 12 | size_t size() const { return N_; } 13 | T& operator[](size_t i) { return buffer_[i]; } 14 | const T& operator[](size_t i) const { return buffer_[i]; } 15 | T* begin() const { return buffer_; } 16 | T* end() const { return buffer_ + N_; } 17 | 18 | private: 19 | const size_t N_; 20 | T* const buffer_; 21 | }; 22 | 23 | template