diff --git a/Chapter-16/16.53.cpp b/Chapter-16/16.53.cpp new file mode 100644 index 0000000..026a681 --- /dev/null +++ b/Chapter-16/16.53.cpp @@ -0,0 +1,24 @@ +#include +#include + +template +std::ostream & print(std::ostream & os, const T & t) +{ + return os << t; +} + +template +std::ostream & print(std::ostream & os, const T & t, const Args & ... rest) +{ + os << t << ", "; + return print(os, rest...); +} + +int main() +{ + print(std::cout, 1) << std::endl; + print(std::cout, 1, "123") << std::endl; + print(std::cout, 1, "123", 3.123, std::string("qwert"), -5) << std::endl; + return 0; +} + diff --git a/Chapter-16/16.56.cpp b/Chapter-16/16.56.cpp new file mode 100644 index 0000000..34e4a92 --- /dev/null +++ b/Chapter-16/16.56.cpp @@ -0,0 +1,74 @@ +#include +#include +#include + +template std::ostream & print(std::ostream & os, const T & t); +template std::ostream & print(std::ostream & os, const T & t, const Args & ... rest); +template std::string debug_rep(const T &t); +template std::string debug_rep(T * p); +std::string debug_rep(const std::string &s); +std::string debug_rep(char *p); +std::string debug_rep(const char *p); +template std::ostream & errorMsg(std::ostream & os, const Args & ... rest); + +template +std::ostream & print(std::ostream & os, const T & t) +{ + return os << t; +} + +template +std::ostream & print(std::ostream & os, const T & t, const Args & ... rest) +{ + os << t << ", "; + return print(os, rest...); +} + +template +std::string debug_rep(const T &t) +{ + std::ostringstream ret; + ret << t; + return ret.str(); +} + +template +std::string debug_rep(T * p) +{ + std::ostringstream ret; + ret << "pointer: " << p; + if(p) + ret << " " << debug_rep(*p); + else + ret << " null pointer"; + return ret.str(); +} + +std::string debug_rep(const std::string &s) +{ + return '"' + s + '"'; +} + +std::string debug_rep(char *p) +{ + return debug_rep(std::string(p)); +} +std::string debug_rep(const char *p) +{ + return debug_rep(std::string(p)); +} + +template +std::ostream & errorMsg(std::ostream & os, const Args & ... rest) +{ + return print(os, debug_rep(rest)...); +} + +int main() +{ + int i = 3; + errorMsg(std::cout, 1, "123", std::string("qwer"), &i) << std::endl; + errorMsg(std::cout, 1) << std::endl; + return 0; +} + diff --git a/Chapter-16/16.58/StrVec/StrVec.cpp b/Chapter-16/16.58/StrVec/StrVec.cpp new file mode 100644 index 0000000..6ff3727 --- /dev/null +++ b/Chapter-16/16.58/StrVec/StrVec.cpp @@ -0,0 +1,198 @@ +#include +#include +#include +#include +#include +#include +#include "StrVec.h" + +std::allocator StrVec::alloc; + +void StrVec::push_back(const std::string &s) +{ + chk_n_alloc(); + alloc.construct(first_free++, s); +} + +void StrVec::push_back(std::string &&s) +{ + chk_n_alloc(); + alloc.construct(first_free++, std::move(s)); +} + +std::pair StrVec::alloc_n_copy(const std::string *b, const std::string *e) +{ + std::string * data = alloc.allocate(e - b); + return {data, std::uninitialized_copy(b, e, data)}; +} + +void StrVec::free() +{ + if(elements) + { + StrVec * th = this; + std::for_each(elements, first_free, [](std::string &s){ alloc.destroy(&s); } ); + alloc.deallocate(elements, cap - elements); + } +} + +StrVec::StrVec(const StrVec & s) +{ + std::pair newdata = alloc_n_copy(s.begin(), s.end()); + elements = newdata.first; + first_free = cap = newdata.second; +} + +StrVec::~StrVec() +{ + free(); +} + +StrVec & StrVec::operator=(const StrVec & rhs) +{ + std::pair data = alloc_n_copy(rhs.begin(), rhs.end()); + free(); + elements = data.first; + first_free = cap = data.second; + return *this; +} + +StrVec & StrVec::operator=(std::initializer_list li) +{ + std::pair data = alloc_n_copy(li.begin(), li.end()); + free(); + elements = data.first; + first_free = cap = data.second; + return *this; +} + +StrVec::StrVec(std::initializer_list li) +{ + std::pair newdata = alloc_n_copy(li.begin(), li.end()); + elements = newdata.first; + first_free = cap = newdata.second; +} + +StrVec::StrVec(StrVec &&s) noexcept : elements(s.elements), first_free(s.first_free), cap(s.cap) +{ + s.elements = s.first_free = s.cap = nullptr; +} + +StrVec & StrVec::operator=(StrVec &&rhs) noexcept +{ + if(this != &rhs) + { + free(); + elements = rhs.elements; + first_free = rhs.first_free; + cap = rhs.cap; + rhs.elements = rhs.first_free = rhs.cap = nullptr; + } + return *this; +} + +void StrVec::reallocate() +{ + size_t newcapacity = size() ? 2 * size() : 1; + reserve(newcapacity); +} + +void StrVec::reserve(size_t n) +{ + if(n <= capacity()) + return; + std::string * newdata = alloc.allocate(n); + std::string * dest = newdata; + std::string * elem = elements; + for(size_t i = 0; i != size(); ++i) + alloc.construct(dest++, std::move(*elem++)); + free(); + elements = newdata; + first_free = dest; + cap = elements + n; +} + +void StrVec::resize(size_t n, const std::string &t) +{ + if(n == size()) + return; + if(n < size()) + { + while(size() != n) + alloc.destroy(--first_free); + return; + } + if(n > capacity()) + reserve(n); + while(size() != n) + alloc.construct(first_free++, t); +} + +bool operator==(const StrVec &lhs, const StrVec &rhs) +{ + if(lhs.size() != rhs.size()) + return false; + for(const std::string *p1 = lhs.begin(), *p2 = rhs.begin(); p1 != lhs.end(); ++p1, ++p2) + if(*p1 != *p2) + return false; + return true; +} + +bool operator!=(const StrVec &lhs, const StrVec &rhs) +{ + return !(lhs == rhs); +} + +bool operator<(const StrVec &lhs, const StrVec &rhs) +{ + const std::string *p1 = lhs.begin(), *p2 = rhs.begin(); + for( ; p1 != lhs.end() && p2 != rhs.end(); ++p1, ++p2) + { + if(*p1 < *p2) + return true; + if(*p1 > *p2) + return false; + } + if(p1 != lhs.end() && p2 == rhs.end()) + return false; + if(p1 == lhs.end() && p2 != rhs.end()) + return true; + return false; +} + +bool operator<=(const StrVec &lhs, const StrVec &rhs) +{ + return !(lhs > rhs); +} + +bool operator>(const StrVec &lhs, const StrVec &rhs) +{ + const std::string *p1 = lhs.begin(), *p2 = rhs.begin(); + for( ; p1 != lhs.end() && p2 != rhs.end(); ++p1, ++p2) + { + if(*p1 > *p2) + return true; + if(*p1 < *p2) + return false; + } + if(p1 != lhs.end() && p2 == rhs.end()) + return true; + if(p1 == lhs.end() && p2 != rhs.end()) + return false; + return false; +} + +bool operator>=(const StrVec &lhs, const StrVec &rhs) +{ + return !(lhs < rhs); +} + +std::string & StrVec::operator[](std::size_t n) +{ + return elements[n]; +} + +const std::string & StrVec::operator[](std::size_t n) const +{ + return elements[n]; +} diff --git a/Chapter-16/16.58/StrVec/StrVec.h b/Chapter-16/16.58/StrVec/StrVec.h new file mode 100644 index 0000000..a609cf2 --- /dev/null +++ b/Chapter-16/16.58/StrVec/StrVec.h @@ -0,0 +1,72 @@ +#ifndef STRVEC_H +#define STRVEC_H + +#include +#include +#include +#include + +class StrVec +{ + friend bool operator==(const StrVec &lhs, const StrVec &rhs); + friend bool operator<(const StrVec &lhs, const StrVec &rhs); + friend bool operator>(const StrVec &lhs, const StrVec &rhs); +public: + + StrVec() : elements(nullptr), first_free(nullptr), cap(nullptr) { } + StrVec(const StrVec &); + StrVec & operator=(const StrVec &); + ~StrVec(); + StrVec(std::initializer_list li); + + StrVec(StrVec &&s) noexcept; + StrVec & operator=(StrVec &&rhs) noexcept; + StrVec & operator=(std::initializer_list li); + + std::string & operator[](std::size_t n); + const std::string & operator[](std::size_t n) const; + + void push_back(const std::string &); + void push_back(std::string &&); + template void emplace_back(Args && ... args); + + size_t size() const { return first_free - elements; } + size_t capacity() const { return cap - elements; } + std::string *begin() const { return elements; } + std::string *end() const { return first_free; } + + void reserve(size_t); + void resize(size_t n, const std::string &t = std::string()); +private: + + static std::allocator alloc; + void chk_n_alloc() + { + if(size() == capacity()) + reallocate(); + } + std::pair alloc_n_copy(const std::string *, const std::string *); + void free(); + void reallocate(); + + std::string * elements; + std::string * first_free; + std::string * cap; +}; + +bool operator==(const StrVec &lhs, const StrVec &rhs); +bool operator!=(const StrVec &lhs, const StrVec &rhs); +bool operator<(const StrVec &lhs, const StrVec &rhs); +bool operator<=(const StrVec &lhs, const StrVec &rhs); +bool operator>(const StrVec &lhs, const StrVec &rhs); +bool operator>=(const StrVec &lhs, const StrVec &rhs); + + +template +void StrVec::emplace_back(Args && ... args) +{ + chk_n_alloc(); + alloc.construct(first_free++, std::forward(args)...); +} + +#endif diff --git a/Chapter-16/16.58/StrVec/main.cpp b/Chapter-16/16.58/StrVec/main.cpp new file mode 100644 index 0000000..38c5089 --- /dev/null +++ b/Chapter-16/16.58/StrVec/main.cpp @@ -0,0 +1,64 @@ +#include +#include +#include +#include "StrVec.h" + +int main() +{ + StrVec v; + v.push_back("123"); + v.push_back("456"); + v.push_back("789"); + v = v; + v = {"123", "456", "789"}; + StrVec v1 = v; + for(std::string * p = v1.begin(); p != v1.end(); ++p) + std::cout << *p << " "; + std::cout << std::endl; + + v1.reserve(10); + std::cout << v1.size() << " " << v1.capacity() << std::endl; + v1.resize(20, "q"); + std::cout << v1.size() << " " << v1.capacity() << std::endl; + for(std::string * p = v1.begin(); p != v1.end(); ++p) + std::cout << *p << " | "; + v1.resize(5); + std::cout << v1.size() << " " << v1.capacity() << std::endl; + for(std::string * p = v1.begin(); p != v1.end(); ++p) + std::cout << *p << " | "; + std::cout << std::endl; + StrVec v2 = {"1","2","3"}; + for(std::string * p = v2.begin(); p != v2.end(); ++p) + std::cout << *p << " | "; + std::cout << std::endl; + + StrVec v5(std::move(v2)); + for(std::string * p = v5.begin(); p != v5.end(); ++p) + std::cout << *p << " | "; + std::cout << std::endl; + + v = std::move(v5); + for(std::string * p = v.begin(); p != v.end(); ++p) + std::cout << *p << " | "; + std::cout << std::endl; + for(std::string * p = v5.begin(); p != v5.end(); ++p) + std::cout << *p << " | "; + std::cout << std::endl; + std::cout << (v == v5) << " " << (v > v5) << " " << (v < v5) << " " << (v <= v5) << " " << (v >= v5) << " " << std::endl; + v[1] = "12"; + std::cout << v[0] << " "<< v[1] << std::endl; + v.emplace_back(10,'c'); + for(std::string * p = v.begin(); p != v.end(); ++p) + std::cout << *p << " | "; + std::cout << std::endl; + return 0; +} + + + + + + + + + diff --git a/Chapter-16/16.58/Vec/Vec.h b/Chapter-16/16.58/Vec/Vec.h new file mode 100644 index 0000000..a314f90 --- /dev/null +++ b/Chapter-16/16.58/Vec/Vec.h @@ -0,0 +1,295 @@ +#ifndef VEC_H +#define VEC_H + +#include +#include +#include +#include +#include + +template class Vec; + +template +bool operator==(const Vec &lhs, const Vec &rhs); +template +bool operator!=(const Vec &lhs, const Vec &rhs); +template +bool operator<(const Vec &lhs, const Vec &rhs); +template +bool operator<=(const Vec &lhs, const Vec &rhs); +template +bool operator>(const Vec &lhs, const Vec &rhs); +template +bool operator>=(const Vec &lhs, const Vec &rhs); + +template +class Vec +{ + friend bool operator== (const Vec &lhs, const Vec &rhs); + friend bool operator< (const Vec &lhs, const Vec &rhs); + friend bool operator> (const Vec &lhs, const Vec &rhs); +public: + + Vec() : elements(nullptr), first_free(nullptr), cap(nullptr) { } + Vec(const Vec &); + Vec & operator=(const Vec &); + ~Vec(); + Vec(std::initializer_list li); + + Vec(Vec &&s) noexcept; + Vec & operator=(Vec &&rhs) noexcept; + Vec & operator=(std::initializer_list li); + + T & operator[](std::size_t n); + const T & operator[](std::size_t n) const; + + void push_back(const T &); + void push_back(T &&); + size_t size() const { return first_free - elements; } + size_t capacity() const { return cap - elements; } + T *begin() const { return elements; } + T *end() const { return first_free; } + + template void emplace_back(Args && ... args); + + void reserve(size_t); + void resize(size_t n, const T &t = T()); +private: + + static std::allocator alloc; + void chk_n_alloc() + { + if(size() == capacity()) + reallocate(); + } + std::pair alloc_n_copy(const T *, const T *); + void free(); + void reallocate(); + + T * elements; + T * first_free; + T * cap; +}; + +template +std::allocator Vec::alloc; + +template +void Vec::push_back(const T &s) +{ + chk_n_alloc(); + alloc.construct(first_free++, s); +} + +template +void Vec::push_back(T &&s) +{ + chk_n_alloc(); + alloc.construct(first_free++, std::move(s)); +} + +template +std::pair Vec::alloc_n_copy(const T *b, const T *e) +{ + T * data = alloc.allocate(e - b); + return {data, std::uninitialized_copy(b, e, data)}; +} + +template +void Vec::free() +{ + if(elements) + { + Vec * th = this; + std::for_each(elements, first_free, [](T &s){ alloc.destroy(&s); } ); + alloc.deallocate(elements, cap - elements); + } +} + +template +Vec::Vec(const Vec & s) +{ + std::pair newdata = alloc_n_copy(s.begin(), s.end()); + elements = newdata.first; + first_free = cap = newdata.second; +} + +template +Vec::~Vec() +{ + free(); +} + +template +Vec & Vec::operator=(const Vec & rhs) +{ + std::pair data = alloc_n_copy(rhs.begin(), rhs.end()); + free(); + elements = data.first; + first_free = cap = data.second; + return *this; +} + +template +Vec & Vec::operator=(std::initializer_list li) +{ + std::pair data = alloc_n_copy(li.begin(), li.end()); + free(); + elements = data.first; + first_free = cap = data.second; + return *this; +} + +template +Vec::Vec(std::initializer_list li) +{ + std::pair newdata = alloc_n_copy(li.begin(), li.end()); + elements = newdata.first; + first_free = cap = newdata.second; +} + +template +Vec::Vec(Vec &&s) noexcept : elements(s.elements), first_free(s.first_free), cap(s.cap) +{ + s.elements = s.first_free = s.cap = nullptr; +} + +template +Vec & Vec::operator=(Vec &&rhs) noexcept +{ + if(this != &rhs) + { + free(); + elements = rhs.elements; + first_free = rhs.first_free; + cap = rhs.cap; + rhs.elements = rhs.first_free = rhs.cap = nullptr; + } + return *this; +} + +template +void Vec::reallocate() +{ + size_t newcapacity = size() ? 2 * size() : 1; + reserve(newcapacity); +} + +template +void Vec::reserve(size_t n) +{ + if(n <= capacity()) + return; + T * newdata = alloc.allocate(n); + T * dest = newdata; + T * elem = elements; + for(size_t i = 0; i != size(); ++i) + alloc.construct(dest++, std::move(*elem++)); + free(); + elements = newdata; + first_free = dest; + cap = elements + n; +} + +template +void Vec::resize(size_t n, const T &t) +{ + if(n == size()) + return; + if(n < size()) + { + while(size() != n) + alloc.destroy(--first_free); + return; + } + if(n > capacity()) + reserve(n); + while(size() != n) + alloc.construct(first_free++, t); +} + +template +bool operator==(const Vec &lhs, const Vec &rhs) +{ + if(lhs.size() != rhs.size()) + return false; + for(const T *p1 = lhs.begin(), *p2 = rhs.begin(); p1 != lhs.end(); ++p1, ++p2) + if(*p1 != *p2) + return false; + return true; +} + +template +bool operator!=(const Vec &lhs, const Vec &rhs) +{ + return !(lhs == rhs); +} + +template +bool operator<(const Vec &lhs, const Vec &rhs) +{ + const T *p1 = lhs.begin(), *p2 = rhs.begin(); + for( ; p1 != lhs.end() && p2 != rhs.end(); ++p1, ++p2) + { + if(*p1 < *p2) + return true; + if(*p1 > *p2) + return false; + } + if(p1 != lhs.end() && p2 == rhs.end()) + return false; + if(p1 == lhs.end() && p2 != rhs.end()) + return true; + return false; +} + +template +bool operator<=(const Vec &lhs, const Vec &rhs) +{ + return !(lhs > rhs); +} + +template +bool operator>(const Vec &lhs, const Vec &rhs) +{ + const T *p1 = lhs.begin(), *p2 = rhs.begin(); + for( ; p1 != lhs.end() && p2 != rhs.end(); ++p1, ++p2) + { + if(*p1 > *p2) + return true; + if(*p1 < *p2) + return false; + } + if(p1 != lhs.end() && p2 == rhs.end()) + return true; + if(p1 == lhs.end() && p2 != rhs.end()) + return false; + return false; +} + +template +bool operator>=(const Vec &lhs, const Vec &rhs) +{ + return !(lhs < rhs); +} + +template +T & Vec::operator[](std::size_t n) +{ + return elements[n]; +} + +template +const T & Vec::operator[](std::size_t n) const +{ + return elements[n]; +} +template +template +void Vec::emplace_back(Args && ... args) +{ + chk_n_alloc(); + alloc.construct(first_free++, std::forward(args)...); +} + +#endif diff --git a/Chapter-16/16.58/Vec/main.cpp b/Chapter-16/16.58/Vec/main.cpp new file mode 100644 index 0000000..13157f0 --- /dev/null +++ b/Chapter-16/16.58/Vec/main.cpp @@ -0,0 +1,71 @@ +#include +#include +#include +#include "Vec.h" + + +int main() +{ + Vec v111; + v111.push_back(1); + std::cout << v111[0] << std::endl; + + using StrVec = Vec; + StrVec v; + v.push_back("123"); + v.push_back("456"); + v.push_back("789"); + v = v; + v = {"123", "456", "789"}; + StrVec v1 = v; + for(std::string * p = v1.begin(); p != v1.end(); ++p) + std::cout << *p << " "; + std::cout << std::endl; + + v1.reserve(10); + std::cout << v1.size() << " " << v1.capacity() << std::endl; + v1.resize(20, "q"); + std::cout << v1.size() << " " << v1.capacity() << std::endl; + for(std::string * p = v1.begin(); p != v1.end(); ++p) + std::cout << *p << " | "; + v1.resize(5); + std::cout << v1.size() << " " << v1.capacity() << std::endl; + for(std::string * p = v1.begin(); p != v1.end(); ++p) + std::cout << *p << " | "; + std::cout << std::endl; + StrVec v2 = {"1","2","3"}; + for(std::string * p = v2.begin(); p != v2.end(); ++p) + std::cout << *p << " | "; + std::cout << std::endl; + + StrVec v5(std::move(v2)); + for(std::string * p = v5.begin(); p != v5.end(); ++p) + std::cout << *p << " | "; + std::cout << std::endl; + + v = std::move(v5); + for(std::string * p = v.begin(); p != v.end(); ++p) + std::cout << *p << " | "; + std::cout << std::endl; + for(std::string * p = v5.begin(); p != v5.end(); ++p) + std::cout << *p << " | "; + std::cout << std::endl; + std::cout << (v == v5) << " " << (v > v5) << " " << (v < v5) << " " << (v <= v5) << " " << (v >= v5) << " " << std::endl; + v[1] = "12"; + std::cout << v[0] << " "<< v[1] << std::endl; + v.emplace_back(10,'c'); + for(std::string * p = v.begin(); p != v.end(); ++p) + std::cout << *p << " | "; + std::cout << std::endl; + return 0; +} + + + + + + + + + + diff --git a/Chapter-16/16.61/DebugDelete.h b/Chapter-16/16.61/DebugDelete.h new file mode 100644 index 0000000..9d53042 --- /dev/null +++ b/Chapter-16/16.61/DebugDelete.h @@ -0,0 +1,16 @@ +#ifndef DEBUGDELETE_H +#define DEBUGDELETE_H + +#include + +class DebugDelete +{ +public: + DebugDelete(std::ostream &s = std::cerr) : os(s) { } + template void operator()(T *p) const { os << "deleting ptr" << std::endl; delete p; } +private: + std::ostream & os; +}; + + +#endif diff --git a/Chapter-16/16.61/main.cpp b/Chapter-16/16.61/main.cpp new file mode 100644 index 0000000..8c87b9c --- /dev/null +++ b/Chapter-16/16.61/main.cpp @@ -0,0 +1,29 @@ +#include +#include +#include + +#include "shared_ptr2.h" +#include "DebugDelete.h" + +template class shared_ptr2; + +int main() +{ + shared_ptr2 sp(new int(3), DebugDelete()) ,sp1;; + shared_ptr2 ssp(new std::string("12345")); + std::cout << *sp << std::endl; + std::cout << sp.unique() << " " << sp.use_count() << " " << *(sp.get()) << std::endl; + std::cout << ssp.unique() << " " << ssp.use_count() << " " << *(ssp.get()) << std::endl; + sp = sp; + sp1 = sp; + std::cout << sp1.unique() << " " << sp1.use_count() << " " << *(sp1.get()) << std::endl; + sp1 = std::move(sp); + std::cout << sp1.unique() << " " << sp1.use_count() << " " << *(sp1.get()) << std::endl; + ssp.reset(new std::string("qwert"), DebugDelete()); + std::cout << ssp.unique() << " " << ssp.use_count() << " " << *(ssp.get()) << std::endl; + + ssp = make_shared2(10, '3'); + std::cout << *ssp << std::endl; + return 0; +} + diff --git a/Chapter-16/16.61/shared_ptr2.h b/Chapter-16/16.61/shared_ptr2.h new file mode 100644 index 0000000..1c5a65e --- /dev/null +++ b/Chapter-16/16.61/shared_ptr2.h @@ -0,0 +1,187 @@ +#ifndef SHARED_PTR2_H +#define SHARED_PTR2_H + +#include +#include +#include + +template class shared_ptr2; + +template +void swap(shared_ptr2 & lhs, shared_ptr2 & rhs); + +template +class shared_ptr2 +{ +public: + shared_ptr2() : p(nullptr), ip(nullptr), delFun(nullptr) { } + shared_ptr2(T * tp, std::function fp = nullptr) : p(tp), ip(new int(1)), delFun(fp) { } + ~shared_ptr2(); + shared_ptr2(const shared_ptr2 & sp, std::function fp = nullptr); + shared_ptr2 & operator=(const shared_ptr2 &); + shared_ptr2(shared_ptr2 && sp, std::function fp = nullptr); + shared_ptr2 & operator=(shared_ptr2 &&); + void swap(shared_ptr2 & sp); + + T * get() const { return p; }; + T & operator*() const; + T * operator->() const; + explicit operator bool() const; + + bool unique() const; + int use_count() const; + void reset(T * sptr = nullptr, std::function fp = nullptr); + +private: + void destroy(); + + T * p; + int * ip; + std::function delFun; +}; + +template +shared_ptr2 make_shared2(Args && ... args) +{ + T * p = new T(std::forward(args)...); + return shared_ptr2(p); +} + +template +shared_ptr2::~shared_ptr2() +{ + destroy(); +} + +template +void shared_ptr2::destroy() +{ + if(ip != nullptr && p != nullptr && --*ip == 0) + { + delFun ? delFun(p) : delete p; + p = nullptr; + delete ip; + ip = nullptr; + delFun = nullptr; + } +} + +template +shared_ptr2::shared_ptr2(const shared_ptr2 & sp, std::function fp) : p(sp.p), ip(sp.ip) +{ + ++*ip; + if(fp == nullptr) + delFun = sp.delFun; + else + delFun = fp; +} + +template +shared_ptr2 & shared_ptr2::operator=(const shared_ptr2 & rhs) +{ + if(p != rhs.p) + { + destroy(); + p = rhs.p; + ip = rhs.ip; + delFun = rhs.delFun; + ++*ip; + } + return *this; +} + +template +shared_ptr2::shared_ptr2(shared_ptr2 && sp, std::function fp) : p(std::move(sp.p)), ip(std::move(sp.ip)) +{ + if(fp == nullptr) + delFun = sp.delFun; + else + delFun = fp; + sp.p = nullptr; + sp.ip =nullptr; + sp.delFun = nullptr; +} + +template +shared_ptr2 & shared_ptr2::operator=(shared_ptr2 && rhs) +{ + if(p != rhs.p) + { + destroy(); + p = std::move(rhs.p); + ip = std::move(rhs.ip); + delFun = std::move(rhs.delFun); + rhs.p = nullptr; + rhs.ip = nullptr; + rhs.delFun =nullptr; + } + else if(this != &rhs) + rhs.destroy(); + return *this; +} + +template +int shared_ptr2::use_count() const +{ + if(ip != nullptr) + return *ip; + throw std::runtime_error("no count!"); +} + +template +bool shared_ptr2::unique() const +{ + if(use_count() == 1) + return true; + return false; +} + +template +T & shared_ptr2::operator*() const +{ + if(p == nullptr) + throw std::runtime_error("no object!"); + return *p; +} + +template +T * shared_ptr2::operator->() const +{ + return & this->operator*(); +} + +template +shared_ptr2::operator bool() const +{ + if(p == nullptr) + return false; + return true; +} + +template +void swap(shared_ptr2 & lhs, shared_ptr2 & rhs) +{ + lhs.swap(rhs); +} + +template +void shared_ptr2::swap(shared_ptr2 & sp) +{ + using std::swap; + swap(p, sp.p); + swap(ip, sp.ip); + swap(delFun, sp.delFun); +} + +template +void shared_ptr2::reset(T * sptr, std::function fp) +{ + destroy(); + p = sptr; + if(p != nullptr) + ip = new int(1); + delFun = fp; +} + + +#endif diff --git a/Chapter-16/16.62/Sales_data.cpp b/Chapter-16/16.62/Sales_data.cpp new file mode 100644 index 0000000..279bc24 --- /dev/null +++ b/Chapter-16/16.62/Sales_data.cpp @@ -0,0 +1,69 @@ +#include +#include +#include +#include "Sales_data.h" + +Sales_data & Sales_data::operator+=(const Sales_data & sa) +{ + amount += sa.amount; + totalPrice += sa.totalPrice; + return *this; +} + +Sales_data & Sales_data::operator=(const std::string & s) +{ + ISBN = s; + totalPrice = 0.0; + amount = 0; + return *this; +} + +inline double Sales_data::avg_price() const +{ + if(amount) + return totalPrice / amount; + return 0; +} + +Sales_data operator+(const Sales_data & sa, const Sales_data & sb) +{ + Sales_data sum = sa; + sum += sb; + return sum; +} + +std::istream & operator>>(std::istream & is, Sales_data & sa) +{ + double price = 0; + is >> sa.ISBN >> sa.amount >> price; + if(is) + sa.totalPrice = price * sa.amount; + else + sa = Sales_data(); + return is; +} + +std::ostream & operator<<(std::ostream & os, const Sales_data & sa) +{ + os << sa.isbn() << " " << sa.amount << " " << sa.totalPrice << " " << sa.avg_price(); + return os; +} + +bool operator==(const Sales_data &lhs, const Sales_data &rhs) +{ + return lhs.isbn() == rhs.isbn() && lhs.totalPrice == rhs.totalPrice && lhs.amount == rhs.amount; +} + +bool operator!=(const Sales_data &lhs, const Sales_data &rhs) +{ + return !(lhs == rhs); +} + +namespace std +{ + size_t hash::operator()(const Sales_data & s) const + { + return hash()(s.ISBN) ^ hash()(s.totalPrice) ^ hash()(s.amount); + } +} + diff --git a/Chapter-16/16.62/Sales_data.h b/Chapter-16/16.62/Sales_data.h new file mode 100644 index 0000000..f99d41d --- /dev/null +++ b/Chapter-16/16.62/Sales_data.h @@ -0,0 +1,62 @@ +#ifndef SALES_DATA_H +#define SALES_DATA_H + +#include +#include +#include + +struct Sales_data; + +Sales_data operator+(const Sales_data & sa, const Sales_data & sb); +std::istream & operator>>(std::istream & is, Sales_data & sa); +std::ostream & operator<<(std::ostream & os, const Sales_data & sa); +bool operator==(const Sales_data &lhs, const Sales_data &rhs); +bool operator!=(const Sales_data &lhs, const Sales_data &rhs); + +template class std::hash; + +class Sales_data +{ +friend class std::hash; +friend Sales_data operator+(const Sales_data & sa, const Sales_data & sb); +friend std::istream & operator>>(std::istream & is, Sales_data & sa); +friend std::ostream & operator<<(std::ostream & os, const Sales_data & sa); +friend bool operator==(const Sales_data &lhs, const Sales_data &rhs); +public: + + Sales_data() = default; + Sales_data(const std::string &s) : ISBN(s) { } + Sales_data(const std::string &s, int a, double t) : ISBN(s), amount(a), totalPrice(t * a) { } + Sales_data(std::istream &is) { is >> *this; } + + std::string isbn() const { return ISBN; } + Sales_data & operator+=(const Sales_data & sa); + Sales_data & operator=(const std::string & s); + + explicit operator double() const { return totalPrice; } + explicit operator std::string() const { return isbn(); } + +private: + + std::string ISBN; + double totalPrice = 0.0; + int amount = 0; + + inline double avg_price() const; +}; + +namespace std +{ + template<> + struct hash + { + typedef size_t result_type; + typedef Sales_data argument_type; + size_t operator()(const Sales_data & s) const; + }; +} + + +#endif + + diff --git a/Chapter-16/16.62/main.cpp b/Chapter-16/16.62/main.cpp new file mode 100644 index 0000000..a78eccc --- /dev/null +++ b/Chapter-16/16.62/main.cpp @@ -0,0 +1,15 @@ +#include +#include +#include +#include "Sales_data.h" + +int main() +{ + std::unordered_multiset SDset; + SDset.emplace("123", 4, 5); + SDset.emplace("234", 5, 6); + for(std::unordered_multiset::iterator ip = SDset.begin(); ip != SDset.end(); ++ip) + std::cout << *ip << std::endl; + return 0; +} + diff --git a/Chapter-16/16.63.cpp b/Chapter-16/16.63.cpp new file mode 100644 index 0000000..43c6aca --- /dev/null +++ b/Chapter-16/16.63.cpp @@ -0,0 +1,25 @@ +#include +#include +#include + +template +size_t vectorFind(const std::vector & v, const T & t) +{ + size_t count = 0; + for(auto p = v.cbegin(); p != v.cend(); ++p) + if(*p == t) + ++count; + return count; +} + +int main() +{ + std::vector vd{1.0, 2.3, 3.5, 2.3}; + std::cout << vectorFind(vd, 2.3) << std::endl; + std::vector vi{1, 2, 3, 2}; + std::cout << vectorFind(vi, 2) << std::endl; + std::vector vs{"1.0", "2.3", "3.5", "2.3"}; + std::cout << vectorFind(vs, std::string("2.3")) << std::endl; + return 0; +} + diff --git a/Chapter-16/16.64.cpp b/Chapter-16/16.64.cpp new file mode 100644 index 0000000..d5116bc --- /dev/null +++ b/Chapter-16/16.64.cpp @@ -0,0 +1,39 @@ +#include +#include +#include +#include + +template +size_t vectorFind(const std::vector & v, const T & t) +{ + size_t count = 0; + for(auto p = v.cbegin(); p != v.cend(); ++p) + if(*p == t) + ++count; + return count; +} + +template <> +size_t vectorFind(const std::vector & v, const char * const & t) +{ + size_t count = 0; + for(auto p = v.cbegin(); p != v.cend(); ++p) + if(strcmp(*p, t) == 0) + ++count; + return count; +} + +int main() +{ + std::vector vd{1.0, 2.3, 3.5, 2.3}; + std::cout << vectorFind(vd, 2.3) << std::endl; + std::vector vi{1, 2, 3, 2}; + std::cout << vectorFind(vi, 2) << std::endl; + std::vector vs{"1.0", "2.3", "3.5", "2.3"}; + std::cout << vectorFind(vs, std::string("2.3")) << std::endl; + const char * p = "2.3"; + std::vector vc{"1.0", "2.3", "3.5", "2.3"}; + std::cout << vectorFind(vc, p) << std::endl; + return 0; +} + diff --git a/Chapter-16/16.65.cpp b/Chapter-16/16.65.cpp new file mode 100644 index 0000000..48cdd88 --- /dev/null +++ b/Chapter-16/16.65.cpp @@ -0,0 +1,59 @@ +#include +#include +#include + +template std::string debug_rep(const T &t); +template std::string debug_rep(T * p); +std::string debug_rep(const std::string &s); +//std::string debug_rep(char *p); +//std::string debug_rep(const char *p); + +template +std::string debug_rep(const T &t) +{ + std::ostringstream ret; + ret << t; + return ret.str(); +} + +template +std::string debug_rep(T * p) +{ + std::ostringstream ret; + ret << "pointer: " << p; + if(p) + ret << " " << debug_rep(*p); + else + ret << " null pointer"; + return ret.str(); +} + +std::string debug_rep(const std::string &s) +{ + return '"' + s + '"'; +} + +template <> +std::string debug_rep(char * p) +{ + return debug_rep(std::string(p)); +} + +template <> +std::string debug_rep(const char * p) +{ + return debug_rep(std::string(p)); +} + +int main() +{ + std::string s("hi"); + std::string * sp = &s; + std::cout << debug_rep(s) << std::endl; + std::cout << debug_rep(&s) << std::endl; + std::cout << debug_rep(sp) << std::endl; + std::cout << debug_rep("hi world!") << std::endl; + return 0; +} + + diff --git a/Chapter-16/chapter-16-answer.md b/Chapter-16/chapter-16-answer.md index 495ac6b..f984338 100644 --- a/Chapter-16/chapter-16-answer.md +++ b/Chapter-16/chapter-16-answer.md @@ -354,4 +354,82 @@ sizeof...(rest) 为 0 [16.52 程序代码](16.52.cpp) * **练习16.53** +重载的可变参数函数模板的print函数 书上的版本 +[16.53 程序代码](16.53.cpp) + +* **练习16.54** +会发生编译错误 + +* **练习16.55** +调用大于1个的除ostream实参时会发生编译错误。 +因为print可变参数函数递归到只剩一个除ostream实参时,传递给下一个递归的rest中没有任何元素,不能匹配T,因此出现编译错误 + +* **练习16.56** +可变参数函数模板的errorMsg函数 书上的版本 +[16.56 程序代码](16.56.cpp) + +* **练习16.57** +与旧版本相比,新版本可以接受不同的类型的参数,旧版本只能接受相同类型的,而且还必须放在大括号中 +但是新版本需要递归,函数调用次数多,耗费资源多 + +* **练习16.58** +StrVec类 书上的版本 +增加了emplace_back函数 +[16.58 StrVec.h 程序代码](16.58/StrVec/StrVec.h) +[16.58 StrVec.cpp 程序代码](16.58/StrVec/StrVec.cpp) +[16.58 测试程序代码](16.58/StrVec/main.cpp) +Vec类 +增加了emplace_back函数 +[16.58 Vec.h程序代码](16.58/Vec/Vec.h) +[16.58 测试程序代码](16.58/Vec/main.cpp) + +* **练习16.59** +由于s是一个string左值,因此Args中的内容为一个类型,类型为string &,与&& 折叠后为string & +由chk_n_alloc()确定空间足够后,std::forward生成一个左值类型,然后传递给alloc.construct构造一个string对象 +* **练习16.60** +猜想make_shared的实现方式: +make_shared是一个可变参数模板的函数,它的第一个模板类型是需要手动指定的,表示了构造的类型。 +后面的是可变参数模板。函数形参是可变参数模板类型。 +函数内容是new一个对象,用std::forward保持参数类型,然后用指针来构造一个shared_ptr,并返回。 + +* **练习16.61** +shared_ptr2类 +模仿标准库的shared_ptr,自己实现 +增加了make_shared2函数 +[16.61 shared_ptr2.h程序代码](16.61/shared_ptr2.h) +[16.61 DebugDelete.h程序代码](16.61/DebugDelete.h) +[16.61 测试程序代码](16.61/main.cpp) + +* **练习16.62** +Sales_data类 书上的版本 +增加了特例化的hash +测试代码仅本题使用 +[16.62 Sales_data.h程序代码](16.62/Sales_data.h) +[16.62 Sales_data.cpp程序代码](16.62/Sales_data.cpp) +[16.62 测试程序代码](16.62/main.cpp) + +* **练习16.63** +函数模板,统计给定值在vector中出现的次数 +[16.63 程序代码](16.63.cpp) + +* **练习16.64** +函数模板,统计给定值在vector中出现的次数 +增加了处理const char * 的特例化版本 +[16.64 程序代码](16.64.cpp) + +* **练习16.65** +debug_rep模板重载函数 +另char * 和const char * 成为模板的特例化版本 +[16.65 程序代码](16.65.cpp) + +* **练习16.66** +优点: +不会影响重载函数的匹配规则 +缺点 +不能实现重载函数的匹配规则优先级的提升 +需要严格遵守模板的定义规则 + +* **练习16.67** +如果对于之前没特例化的版本来讲,是和之前函数匹配规则不一样 +但是特例化的版本不会提高优先级,因此不会影响正常函数的匹配规则 diff --git a/Chapter-17/chapter-17-answer.md b/Chapter-17/chapter-17-answer.md new file mode 100644 index 0000000..d077411 --- /dev/null +++ b/Chapter-17/chapter-17-answer.md @@ -0,0 +1,2 @@ +* **练习17.1** + diff --git a/README.md b/README.md index 691facb..bf63073 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,8 @@ C++ Primer 第五版中文版 练习题答案代码 * 第十六章 模板与泛型编程 [第十六章 练习题答案](Chapter-16/chapter-16-answer.md) * 第四部分 高级主题 + * 第十七章 标准库特殊设施 + [第十七章 练习题答案](Chapter-17/chapter-17-answer.md) ## 编译环境 * Windows 10