From 14198d81aabc04869a0f1a8c20d63f15c8d8e295 Mon Sep 17 00:00:00 2001 From: pezy Date: Wed, 11 Apr 2018 09:28:34 +0800 Subject: [PATCH 01/11] finished to 16.27 --- .clang-format | 2 +- .gitignore | 2 +- .vscode/launch.json | 2 +- .vscode/settings.json | 15 +- ch16/README.md | 76 ++++- ch16/ex16.17.18/main.cpp | 51 --- ch16/ex16.19.20/main.cpp | 62 ---- ch16/ex16.21.22/DebugDelete.h | 20 -- ch16/ex16.21.22/StrBlob.h | 176 ---------- ch16/ex16.21.22/main.cpp | 35 -- ch16/ex16.21.22/wy_queryresult.cpp | 56 ---- ch16/ex16.21.22/wy_queryresult.h | 63 ---- ch16/ex16.21.22/wy_textquery.cpp | 75 ----- ch16/ex16.21.22/wy_textquery.h | 50 --- ch16/ex16.24/Blob.h | 112 ------- ch16/ex16.24/blobptr.h | 95 ------ ch16/ex16.24/main.cpp | 28 -- ch16/ex16.25.26/main.cpp | 44 --- ch16/ex16_02_compare.h | 11 - ch16/ex16_04_find.h | 11 - ch16/ex16_05_print_array.h | 13 - ch16/ex16_06_begin_end.h | 12 - ch16/ex16_07_sizeof_array.h | 11 - ch16/ex16_12_blob.h | 11 - ch16/ex16_14_screen.h | 12 - ch16/ex16_16_vec.h | 11 - ch16/ex16_19_print_container.cpp | 18 + ch16/ex16_20_print_container_iter.cpp | 17 + ch16/ex16_21_debugdelete.cpp | 18 + ch16/ex16_21_debugdelete.h | 20 ++ ch16/ex16_22_textquery.cpp | 45 +++ ch16/ex16_22_textquery.h | 49 +++ ch16/ex16_22_textquery_test.cpp | 19 ++ ch16/ex16_24_blob.h | 455 ++++++++++++++++++++++++++ ch16/ex16_24_blob_test.cpp | 29 ++ 35 files changed, 752 insertions(+), 974 deletions(-) delete mode 100644 ch16/ex16.17.18/main.cpp delete mode 100644 ch16/ex16.19.20/main.cpp delete mode 100644 ch16/ex16.21.22/DebugDelete.h delete mode 100644 ch16/ex16.21.22/StrBlob.h delete mode 100644 ch16/ex16.21.22/main.cpp delete mode 100644 ch16/ex16.21.22/wy_queryresult.cpp delete mode 100644 ch16/ex16.21.22/wy_queryresult.h delete mode 100644 ch16/ex16.21.22/wy_textquery.cpp delete mode 100644 ch16/ex16.21.22/wy_textquery.h delete mode 100644 ch16/ex16.24/Blob.h delete mode 100644 ch16/ex16.24/blobptr.h delete mode 100644 ch16/ex16.24/main.cpp delete mode 100644 ch16/ex16.25.26/main.cpp create mode 100644 ch16/ex16_19_print_container.cpp create mode 100644 ch16/ex16_20_print_container_iter.cpp create mode 100644 ch16/ex16_21_debugdelete.cpp create mode 100644 ch16/ex16_21_debugdelete.h create mode 100644 ch16/ex16_22_textquery.cpp create mode 100644 ch16/ex16_22_textquery.h create mode 100644 ch16/ex16_22_textquery_test.cpp create mode 100644 ch16/ex16_24_blob.h create mode 100644 ch16/ex16_24_blob_test.cpp diff --git a/.clang-format b/.clang-format index 12e25bfb..79543ca7 100644 --- a/.clang-format +++ b/.clang-format @@ -21,7 +21,7 @@ BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false BinPackParameters: true BinPackArguments: true -ColumnLimit: 80 +ColumnLimit: 100 ConstructorInitializerAllOnOneLineOrOnePerLine: false ConstructorInitializerIndentWidth: 4 DerivePointerAlignment: false diff --git a/.gitignore b/.gitignore index c8a168df..cb7b0c05 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ #vscode -.vs +launch.json # Mac OS .DS_Store diff --git a/.vscode/launch.json b/.vscode/launch.json index 26f0184b..a22e0cff 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -12,7 +12,7 @@ "environment": [], "externalConsole": true, "MIMode": "gdb", - "miDebuggerPath": "C:\\MinGW\\bin\\gdb.exe", + "miDebuggerPath": "D:\\libs\\MinGW\\bin\\gdb.exe", "setupCommands": [ { "description": "Enable pretty-printing for gdb", diff --git a/.vscode/settings.json b/.vscode/settings.json index 73603a7f..5a32a625 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,14 +1,9 @@ { "editor.formatOnSave": true, "files.associations": { - "vector": "cpp", - "iosfwd": "cpp", - "random": "cpp", "xstring": "cpp", - "bitset": "cpp", - "set": "cpp", - "tuple": "cpp", "algorithm": "cpp", + "bitset": "cpp", "cctype": "cpp", "cmath": "cpp", "cstddef": "cpp", @@ -26,6 +21,7 @@ "initializer_list": "cpp", "iomanip": "cpp", "ios": "cpp", + "iosfwd": "cpp", "iostream": "cpp", "istream": "cpp", "iterator": "cpp", @@ -37,18 +33,22 @@ "new": "cpp", "numeric": "cpp", "ostream": "cpp", + "random": "cpp", "regex": "cpp", + "set": "cpp", "sstream": "cpp", "stack": "cpp", "stdexcept": "cpp", "streambuf": "cpp", "string": "cpp", "system_error": "cpp", + "tuple": "cpp", "type_traits": "cpp", "typeinfo": "cpp", "unordered_map": "cpp", "unordered_set": "cpp", "utility": "cpp", + "vector": "cpp", "xfacet": "cpp", "xfunctional": "cpp", "xhash": "cpp", @@ -66,5 +66,6 @@ "xtr1common": "cpp", "xtree": "cpp", "xutility": "cpp" - } + }, + "C_Cpp.errorSquiggles": "Disabled" } \ No newline at end of file diff --git a/ch16/README.md b/ch16/README.md index b6feb6d7..0f3d5421 100644 --- a/ch16/README.md +++ b/ch16/README.md @@ -143,20 +143,69 @@ When we want to inform the compiler that a name represents a type, we must use t Fixed: ```cpp -(a) template void f1(T, U, V); -(b) template T f2(int &); -(c) +(a) template void f1(T, U, V); // identifier 'U' +(b) template T f2(int &); // typename would be hidden +(c) template inline T foo(T, unsigned int*); // inline must be after template +(d) template void f4(T, T); // return type should be provided +(e) typedef char Ctype; +template T f5(Ctype a); // the typename hides this typedef ``` ## Exercise 16.19 > Write a function that takes a reference to a container and prints the elements in that container. Use the container’s `size_type` and `size` members to control the loop that prints the elements. +[print](ex16_19_print_container.cpp) + ## Exercise 16.20 > Rewrite the function from the previous exercise to use iterators returned from `begin` and `end` to control the loop. +[print](ex16_20_print_container_iter.cpp) + +## Exercise 16.21 + +> Write your own version of `DebugDelete`. + +[DebugDelete|h](ex16_21_debugdelete.h) | [DebugDelete|cpp](ex16_21_debugdelete.cpp) + +## Exercise 16.22 + +> Revise your `TextQuery` programs from 12.3 (p. 484) so that the `shared_ptr` members use a `DebugDelete` as their deleter (12.1.4, p. 468). + +[TestQuery|h](ex16_22_textquery.h) | [TestQuery|cpp](ex16_22_textquery.cpp) | [TestQuery|test](ex16_22_textquery_test.cpp) + +## Exercise 16.23 + +> Predict when the call operator will be executed in your main query program. If your expectations and what happens differ, be sure you understand why. + +when input the `q` to quit `runQueries` function. [Exercise 16.22](#exercise-1622)'s output can check this. + +## Exercise 16.24 + +> Add a constructor that takes two iterators to your `Blob` template. + +[Blob|h](ex16_24_blob.h) | [Blob|test](ex16_24_blob_test.cpp) + +## Exercise 16.25 + +> Explain the meaning of these declarations +>```cpp +>extern template class vector; +>template class vector; +>``` + +`vector` instantiation declaration here, it must be instantiated elsewhere in the program. +`vector` instantiates all members of the class template here. + +## Exercise 16.26 + +> Assuming `NoDefault` is a class that does not have a default constructor, can we explicitly instantiate `vector`? If not, why not? + +see + ## Exercise 16.27 + > For each labeled statement explain what, if any, instantiations happen. If a template is instantiated, explain why; if not, explain why not. >```cpp >template class Stack { }; @@ -174,12 +223,29 @@ Fixed: >``` Solution: + - (a) No instantiation, compiles, it got instantiated when called. - (b) No instantiation, compiles, references and pointers doesn't need instantiation - (c) Instantiation. Doesn't compile! - (d) No instantiation, compiles, references and pointers doesn't need instantiation -- (e) Instantiation of Stack. Doesn't compile! -- (f) Instantiation of Stack. Doesn't compileNo instantiation, compiles, references and pointers doesn't need instantiation! +- (e) Instantiation of `Stack`. Doesn't compile! +- (f) Instantiation of `Stack`. Doesn't compileNo instantiation, compiles, references and pointers doesn't need instantiation! Solution from [How is a template instantiated? - Stack Overflow](https://stackoverflow.com/questions/21598635/how-is-a-template-instantiated) +## Exercise 16.28 + +> Write your own versions of `shared_ptr` and `unique_ptr`. + +## Exercise 16.29 + +> Revise your `Blob` class to use your version of `shared_ptr` rather than the library version. + +## Exercise 16.30 + +Rerun some of your programs to verify your `shared_ptr` and revised `Blob` classes. (Note: Implementing the `weak_ptr` type is beyond the scope of this Primer, so you will not be able to use the `BlobPtr` +class with your revised `Blob`.) + +## Exercise 16.31 + +>Explain how the compiler might inline the call to the deleter if we used `DebugDelete` with `unique_ptr`. \ No newline at end of file diff --git a/ch16/ex16.17.18/main.cpp b/ch16/ex16.17.18/main.cpp deleted file mode 100644 index 1bd3080a..00000000 --- a/ch16/ex16.17.18/main.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/*************************************************************************** - * @file main.cpp - * @author Alan.W - * @date 02 Feb 2014 - * @remark This code is for the exercises from C++ Primer 5th Edition - * @note - ***************************************************************************/ -//! -//! Exercise 16.17: -//! What, if any, are the differences between a type parameter that is declared -//! as a typename and one that is declared as a class? When must typename be used? -//! -// There is no difference. typename and class are interchangeable in the -// declaration of a type template parameter. -// You do, however, have to use class (and not typename) when declaring a -// template template parameter. -// -// When we want to inform the compiler that a name represents a type, we must use -// the keyword typename, not class -//! -//! Exercise 16.18: -//! Explain each of the following function template declarations and identify -//! whether any are illegal. Correct each error that you find. -//! - -#include -#include - -template void f1(T, U, V); -//! ^^^^^^^^ added to fix the error - -template T f2(T&); -//! ^^ - -template inline T foo(T, unsigned int*); -//! ^^^^^^ inline must be after template - -template T f4(T, T); -//! ^ -- return type should be provided - -typedef char C; -//! ^ -//!the template declatation below hides this typedef - template Ctype f5(Ctype a); - -int main() -{ - - - return 0; -} diff --git a/ch16/ex16.19.20/main.cpp b/ch16/ex16.19.20/main.cpp deleted file mode 100644 index a4579647..00000000 --- a/ch16/ex16.19.20/main.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/*************************************************************************** - * @file main.cpp - * @author Alan.W - * @date 03 Feb 2014 - * @remark This code is for the exercises from C++ Primer 5th Edition - * @note - ***************************************************************************/ -//! -//! Exercise 16.19: -//! Write a function that takes a reference to a container and prints the -//! elements in that container. Use the container’s size_type and size members -//! to control the loop that prints the elements. -//! -//! Exercise 16.20: -//! Rewrite the function from the previous exercise to use iterators returned -//! from begin and end to control the loop. -//! - -#include -#include -#include - -//! ex16.19 -template -std::ostream& print(Container& c, std::ostream &os); - -//! ex16.20 -template -std::ostream& print2(Container& c, std::ostream &os); - -int main() -{ - std::vector v = {1,23,6,4,5,7,4}; - std::list l = {"ss","sszz","saaas","s333s","ss2","sss"}; - print2(v, std::cout); - print2(l, std::cout); - - return 0; -} - -//! ex16.19 using size() to control the loop -template -std::ostream & print(Container &c, std::ostream &os) -{ - typedef typename Container::size_type size_type; - - auto it = c.begin(); - for(size_type i = 0; i!= c.size(); ++i) - os << *it++ << "\n"; - - return os; -} - -//! ex16.20 using iterator to control the loop -template -std::ostream& print2(Container& c, std::ostream &os) -{ - for (auto it = c.begin(); it != c.end(); ++it) - os << *it << "\n"; - - return os; -} diff --git a/ch16/ex16.21.22/DebugDelete.h b/ch16/ex16.21.22/DebugDelete.h deleted file mode 100644 index 49984703..00000000 --- a/ch16/ex16.21.22/DebugDelete.h +++ /dev/null @@ -1,20 +0,0 @@ -#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 unique_ptr" << std::endl; - delete p; - } - -private: - std::ostream& os; -}; -#endif // DEBUGDELETE_H diff --git a/ch16/ex16.21.22/StrBlob.h b/ch16/ex16.21.22/StrBlob.h deleted file mode 100644 index cbb6f4e5..00000000 --- a/ch16/ex16.21.22/StrBlob.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - * This file contains code from "C++ Primer, Fifth Edition", by Stanley B. - * Lippman, Josee Lajoie, and Barbara E. Moo, and is covered under the - * copyright and warranty notices given in that book: - * - * "Copyright (c) 2013 by Objectwrite, Inc., Josee Lajoie, and Barbara E. Moo." - * - * - * "The authors and publisher have taken care in the preparation of this book, - * but make no expressed or implied warranty of any kind and assume no - * responsibility for errors or omissions. No liability is assumed for - * incidental or consequential damages in connection with or arising out of the - * use of the information or programs contained herein." - * - * Permission is granted for this code to be used for educational purposes in - * association with the book, given proper citation if and when posted or - * reproduced. Any commercial use of this code requires the explicit written - * permission of the publisher, Addison-Wesley Professional, a division of - * Pearson Education, Inc. Send your request for permission, stating clearly - * what code you would like to use, and in what specific way, to the following - * address: - * - * Pearson Education, Inc. - * Rights and Permissions Department - * One Lake Street - * Upper Saddle River, NJ 07458 - * Fax: (201) 236-3290 -*/ - -#ifndef STRBLOB_H -#define STRBLOB_H - -#include -#include -#include -#include -#include - -// forward declaration needed for friend declaration in StrBlob -class StrBlobPtr; - -class StrBlob -{ - friend class StrBlobPtr; -public: - typedef std::vector::size_type size_type; - - // constructors - StrBlob() : data(std::make_shared>()) { } - StrBlob(std::initializer_list il); - - // size operations - size_type size() const { return data->size(); } - bool empty() const { return data->empty(); } - - // add and remove elements - void push_back(const std::string &t) { data->push_back(t); } - void pop_back(); - - // element access - std::string& front(); - std::string& back(); - - // interface to StrBlobPtr - StrBlobPtr begin(); // can't be defined until StrBlobPtr is - StrBlobPtr end(); -private: - std::shared_ptr> data; - // throws msg if data[i] isn't valid - void check(size_type i, const std::string &msg) const; -}; - -// constructor -inline -StrBlob::StrBlob(std::initializer_list il): - data(std::make_shared>(il)) { } - -// StrBlobPtr throws an exception on attempts to access a nonexistent element -class StrBlobPtr -{ - friend bool eq(const StrBlobPtr&, const StrBlobPtr&); -public: - StrBlobPtr(): curr(0) { } - StrBlobPtr(StrBlob &a, size_t sz = 0) : wptr(a.data), curr(sz) { } - - //! newly overloaded why? - StrBlobPtr(const StrBlob &a, const size_t sz = 0) : wptr(a.data), curr(sz) { } - - std::string& deref() const; - StrBlobPtr& incr(); // prefix version - StrBlobPtr& decr(); // prefix version -private: - // check returns a shared_ptr to the vector if the check succeeds - std::shared_ptr> - check(std::size_t, const std::string&) const; - - // store a weak_ptr, which means the underlying vector might be destroyed - std::weak_ptr> wptr; - std::size_t curr; // current position within the array -}; - -inline -std::string& StrBlobPtr::deref() const -{ - auto p = check(curr, "dereference past end"); - return (*p)[curr]; // (*p) is the vector to which this object points -} - -inline -std::shared_ptr> -StrBlobPtr::check(std::size_t i, const std::string &msg) const -{ - auto ret = wptr.lock(); // is the vector still around? - if (!ret) - throw std::runtime_error("unbound StrBlobPtr"); - - if (i >= ret->size()) - throw std::out_of_range(msg); - return ret; // otherwise, return a shared_ptr to the vector -} - -// prefix: return a reference to the incremented object -inline -StrBlobPtr& StrBlobPtr::incr() -{ - // if curr already points past the end of the container, can't increment it - check(curr, "increment past end of StrBlobPtr"); - ++curr; // advance the current state - return *this; -} - -inline -StrBlobPtr& StrBlobPtr::decr() -{ - // if curr is zero, decrementing it will yield an invalid subscript - --curr; // move the current state back one element} - check(-1, "decrement past begin of StrBlobPtr"); - return *this; -} - -// begin and end members for StrBlob -inline -StrBlobPtr -StrBlob::begin() -{ - return StrBlobPtr(*this); -} - -inline -StrBlobPtr -StrBlob::end() -{ - auto ret = StrBlobPtr(*this, data->size()); - return ret; -} - -// named equality operators for StrBlobPtr -inline -bool eq(const StrBlobPtr &lhs, const StrBlobPtr &rhs) -{ - auto l = lhs.wptr.lock(), r = rhs.wptr.lock(); - // if the underlying vector is the same - if (l == r) - // then they're equal if they're both null or - // if they point to the same element - return (!r || lhs.curr == rhs.curr); - else - return false; // if they point to difference vectors, they're not equal -} - -inline -bool neq(const StrBlobPtr &lhs, const StrBlobPtr &rhs) -{ - return !eq(lhs, rhs); -} -#endif diff --git a/ch16/ex16.21.22/main.cpp b/ch16/ex16.21.22/main.cpp deleted file mode 100644 index fdd37874..00000000 --- a/ch16/ex16.21.22/main.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/*************************************************************************** - * @file main.cpp - * @author Alan.W - * @date 03 Feb 2014 - * @remark This code is for the exercises from C++ Primer 5th Edition - * @note - ***************************************************************************/ -//! -//! Exercise 16.21: -//! Write your own version of DebugDelete. -//! -//! Exercise 16.22: -//! Revise your TextQuery programs from § 12.3 (p. 484) so that the shared_ptr -//! members use a DebugDelete as their deleter (§ 12.1.4, p. 468). -//! - -#include -#include -#include - -#include "DebugDelete.h" -#include - -#include "wy_queryresult.h" -#include "wy_textquery.h" - -int main() -{ - - - - - return 0; -} - diff --git a/ch16/ex16.21.22/wy_queryresult.cpp b/ch16/ex16.21.22/wy_queryresult.cpp deleted file mode 100644 index 720cc8e8..00000000 --- a/ch16/ex16.21.22/wy_queryresult.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/*************************************************************************** - * @file wy_queryresult.cpp - * @author Alan.W - * @date 27 DEC 2013 - * @remark - ***************************************************************************/ -//! -//! Exercise 12.27: -//! The TextQuery and QueryResult classes use only capabilities that we have -//! already covered. Without looking ahead, write your own versions of these -//! classes. -//! - - -#include "wy_queryresult.h" - -//! copy constructor -inline wy_queryResult::wy_queryResult(const wy_queryResult &qr): - counter(qr.getCounter()), queryWord(qr.getQueryWord()), - sp_file(qr.getSp_file()), sp_Qmap(qr.getSp_Qmap()) -{ -} - -//! constructor -wy_queryResult::wy_queryResult(std::size_t c, const std::string &str, - const wy_textQuery::sp_file_Tp &sp_f, - const wy_textQuery::sp_Qmap_Tp &sp_m) : - counter(c), queryWord(str), sp_file(sp_f), sp_Qmap(sp_m) -{ -} - -//! a non-member function printing the result of a query. -void print(std::ostream &os, const wy_queryResult &qr) -{ - //! fetch the word being queried. - const std::string queryWord = qr.getQueryWord(); - - //! print the word and occurrence times - os << "The word [" - < - -class wy_queryResult -{ -public: - //! default constructor - wy_queryResult() = default; - - //! copy constructor - wy_queryResult(const wy_queryResult &qr); - - wy_queryResult(std::size_t c, const std::string &str, - const wy_textQuery::sp_file_Tp &sp_f, - const wy_textQuery::sp_Qmap_Tp &sp_m); - - std::size_t - getCounter() const { return counter; } - - std::string - getQueryWord() const { return queryWord; } - - wy_textQuery::sp_file_Tp - getSp_file() const { return sp_file; } - - wy_textQuery::sp_Qmap_Tp - getSp_Qmap() const { return sp_Qmap; } - -private: - - //! number of occurrence - std::size_t counter = 0; - - //! the word being searched - std::string queryWord = ""; - - //! smart pointer to a vector to be storing a file. - wy_textQuery::sp_file_Tp sp_file = nullptr; - - //! smart pointer to a map to be storing results of querries. - wy_textQuery::sp_Qmap_Tp sp_Qmap = nullptr; -}; - -//! print the result of searching -void print(std::ostream &os, const wy_queryResult &qr); - -#endif // WY_QUERYRESULT_H diff --git a/ch16/ex16.21.22/wy_textquery.cpp b/ch16/ex16.21.22/wy_textquery.cpp deleted file mode 100644 index f0fcb715..00000000 --- a/ch16/ex16.21.22/wy_textquery.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/*************************************************************************** - * @file wy_textquery.cpp - * @author Alan.W - * @date 27 DEC 2013 - * @remark 03 FEB 2014 deleter added - ***************************************************************************/ - -//! -//! Exercise 12.27: -//! The TextQuery and QueryResult classes use only capabilities that we have -//! already covered. Without looking ahead, write your own versions of these -//! classes. -//! - -#include "wy_textquery.h" -#include "wy_queryresult.h" -#include "DebugDelete.h" -#include -#include - -/** - * Constructor - * read each line into the dynamicly allocated vector. - */ -wy_textQuery::wy_textQuery(std::ifstream &fin) : - //! @oldcode - //! custom deleter may not use with std::make_shared, as it has an internal - //! deleter which may not be replaced. As a result, keyword new is the only - //! option to use with DebugDelete. - /* - sp_fileData(std::make_shared>() ), - sp_queryMap(std::make_shared>>() ) - */ - sp_fileData(new std::vector(), DebugDelete() ), - sp_queryMap(new std::map>(), DebugDelete()) -{ - std::string line; - while(std::getline(fin, line)) - sp_fileData->push_back(line); - -} - -/** - * @brief return a wy_queryResult object for the search result. - * @param qWord - */ -wy_queryResult -wy_textQuery::query(const std::string &qWord) const -{ - //! storing the amount of occurrence - std::size_t counter = 0; - - //! loop through each line - for(std::size_t i=0; i != sp_fileData->size(); ++i) - { - //! break into each word - std::stringstream lineStream((*sp_fileData)[i]); - std::string word; - while(lineStream >> word) - { - if(!word.compare(qWord)) - { - ++counter; - - //! add the index of the line into the result map - (*sp_queryMap)[qWord].insert(i); - } - } - } - - //! creare a object holding the result . - wy_queryResult qResult(counter, qWord, sp_fileData, sp_queryMap); - - return qResult; -} diff --git a/ch16/ex16.21.22/wy_textquery.h b/ch16/ex16.21.22/wy_textquery.h deleted file mode 100644 index 4a7967f3..00000000 --- a/ch16/ex16.21.22/wy_textquery.h +++ /dev/null @@ -1,50 +0,0 @@ -/*************************************************************************** - * @file wy_textquery.h - * @author Alan.W - * @date 27 DEC 2013 - * @remark - ***************************************************************************/ - -//! -//! Exercise 12.27: -//! The TextQuery and QueryResult classes use only capabilities that we have -//! already covered. Without looking ahead, write your own versions of these -//! classes. -//! - -#ifndef WY_TEXTQUERY_H -#define WY_TEXTQUERY_H - -#include -#include -#include -#include -#include -#include -#include - -class wy_queryResult; - -class wy_textQuery -{ -public: - typedef std::shared_ptr> sp_file_Tp; - typedef std::shared_ptr>> sp_Qmap_Tp; - - //! constructors - wy_textQuery() = default; - wy_textQuery(std::ifstream &fin); - - //! query operation - wy_queryResult - query(const std::string &qWord) const; - -private: - //! smart pointer to a vector to be storing a file. - sp_file_Tp sp_fileData = nullptr; - - //! smart pointer to a map to be storing results of querries. - sp_Qmap_Tp sp_queryMap = nullptr; -}; - -#endif // WY_TEXTQUERY_H diff --git a/ch16/ex16.24/Blob.h b/ch16/ex16.24/Blob.h deleted file mode 100644 index c9781f5e..00000000 --- a/ch16/ex16.24/Blob.h +++ /dev/null @@ -1,112 +0,0 @@ -/*************************************************************************** - * @file Blob.h - * @author Alan.W - * @date 02 Feb 2014 - * @remark This code is for the exercises from C++ Primer 5th Edition - * @note 03 Feb 2014 Add a constructor that takes two iterators to Blob . - ***************************************************************************/ - -#ifndef BLOB_H -#define BLOB_H -#include -#include - -template class Blob -{ -public: - typedef T value_type; - typedef typename std::vector::size_type size_type; - - //! constructors - Blob(); - Blob(std::initializer_list il); - - //! constructor taking two iterators - template - Blob(It b, It e); - - //! number of elements in the Blob - size_type size() const { return data->size(); } - bool empty() const{ return data->empty();} - - void push_back(const T& t) { data->push_back(t); } - void push_back(T&& t) { data->push_back(std::move(t));} - void pop_back(); - - //! element access - T& back(); - T& operator[](size_type i); - - const T& back() const; - const T& operator [](size_type i) const; - -private: - std::shared_ptr> data; - //! throw msg if data[i] isn't valid - void check(size_type i, const std::string &msg) const; -}; - -//! default constructor -template -Blob::Blob() : data(std::make_shared>()) -{} - -//! constructor taking initializer_list -template -Blob::Blob(std::initializer_list il): - data(std::make_shared>(il)){ } - -//! constructor taking two iterators -template //for class -template //for this member -Blob::Blob(It b, It e) : - data(std::make_shared>(b,e)) -{} - -template -void Blob::check(size_type i, const std::string &msg) const -{ - if(i >= data->size()) - throw std::out_of_range(msg); -} - -template -T& Blob::back() -{ - check(0,"back on empty Blob"); - return data->back(); -} - -template -const T& Blob::back() const -{ - check(0,"back on empty Blob"); - return data->back(); -} - - -template -T& Blob::operator [](size_type i) -{ - //! if i is too big, check function will throw,preventing access to a nonexistent element - check(i,"subscript out of range"); - return (*data)[i]; -} - - -template -const T& Blob::operator [](size_type i) const -{ - //! if i is too big, check function will throw,preventing access to a nonexistent element - check(i,"subscript out of range"); - return (*data)[i]; -} - -template -void Blob::pop_back() -{ - check(0,"pop_back on empty Blob"); - data->pop_back(); -} - -#endif // BLOB_H diff --git a/ch16/ex16.24/blobptr.h b/ch16/ex16.24/blobptr.h deleted file mode 100644 index 6d3fd272..00000000 --- a/ch16/ex16.24/blobptr.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef BLOBPTR_H -#define BLOBPTR_H - -#include "Blob.h" -#include -#include - -template class BlobPtr; - -template -bool operator ==(const BlobPtr& lhs, const BlobPtr& rhs); - -template -bool operator < (const BlobPtr& lhs, const BlobPtr& rhs); - - -template class BlobPtr -{ - friend bool operator == - (const BlobPtr& lhs, const BlobPtr& rhs); - - friend bool operator < - (const BlobPtr& lhs, const BlobPtr& rhs); - -public: - BlobPtr() : curr(0) { } - BlobPtr(Blob& a, std::size_t sz = 0) : - wptr(a.data), curr(sz) { } - - T& operator*() const - { - auto p = check(curr, "dereference past end"); - return (*p)[curr]; - } - - //! prefix - BlobPtr& operator++(); - BlobPtr& operator--(); - - //! postfix - BlobPtr operator ++(int); - BlobPtr operator --(int); - -private: - //! returns a shared_ptr to the vector if the check succeeds - std::shared_ptr> - check(std::size_t, const std::string&) const; - - std::weak_ptr> wptr; - std::size_t curr; - -}; - -//! prefix ++ -template -BlobPtr& BlobPtr::operator ++() -{ - //! if curr already points past the end of the container, can't increment it - check(curr,"increment past end of StrBlob"); - ++curr; - return *this; -} - -//! prefix -- -template -BlobPtr& BlobPtr::operator --() -{ - -- curr; - check(curr,"decrement past begin of BlobPtr"); - - return *this; -} - - -//! postfix ++ -template -BlobPtr BlobPtr::operator ++(int) -{ - BlobPtr ret = *this; - ++*this; - - return ret; -} - -//! postfix -- -template -BlobPtr BlobPtr::operator --(int) -{ - BlobPtr ret = *this; - --*this; - - return ret; -} - -#endif // BLOBPTR_H diff --git a/ch16/ex16.24/main.cpp b/ch16/ex16.24/main.cpp deleted file mode 100644 index a9852ce8..00000000 --- a/ch16/ex16.24/main.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/*************************************************************************** - * @file main.cpp - * @author Alan.W - * @date 03 Feb 2014 - * @remark This code is for the exercises from C++ Primer 5th Edition - * @note - ***************************************************************************/ -//! -//! Exercise 16.24: -//! Add a constructor that takes two iterators to your Blob template. -//! - -#include -#include -#include - - -#include -#include - - -int main() -{ - std::vector v = {1,2,3,4,5}; - Blob b(v.begin(), v.end()); - return 0; -} - diff --git a/ch16/ex16.25.26/main.cpp b/ch16/ex16.25.26/main.cpp deleted file mode 100644 index 90a9d43a..00000000 --- a/ch16/ex16.25.26/main.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/*************************************************************************** - * @file main.cpp - * @author Alan.W - * @date 03 Feb 2014 - * @remark This code is for the exercises from C++ Primer 5th Edition - * @note - ***************************************************************************/ -//! -//! Exercise 16.25: -//! Explain the meaning of these declarations: - -/** - * @brief instantiation declaration. The definition of it is somewhere else - */ -//extern template class vector; - -/** - * @brief instantiation definition. The compiler will generate codes for it. - */ -//template class vector; - -//! Exercise 16.26: -//! Assuming NoDefault is a class that does not have a default constructor, -//! can we explicitly instantiate vector? If not, why not? -// http://stackoverflow.com/questions/21525169/while-explicitly-instantiating-vectorsometype-what-is-the-sometype-default-co -//! - - - - -#include -#include -#include - -#include -#include - - -int main() -{ - - return 0; -} - diff --git a/ch16/ex16_02_compare.h b/ch16/ex16_02_compare.h index 7e1e567a..ccb93486 100644 --- a/ch16/ex16_02_compare.h +++ b/ch16/ex16_02_compare.h @@ -1,14 +1,3 @@ -/* -================================================================================ -C++ Primer 5th Exercise Answer Source Code -Copyright (C) 2014-2015 github.com/pezy/CppPrimer - -custom template compare function. - -If you have questions, try to connect with me: pezy -================================================================================ -*/ - #ifndef CP5_EX16_02_COMPARE_H_ #define CP5_EX16_02_COMPARE_H_ diff --git a/ch16/ex16_04_find.h b/ch16/ex16_04_find.h index f05f2562..f0c4a532 100644 --- a/ch16/ex16_04_find.h +++ b/ch16/ex16_04_find.h @@ -1,14 +1,3 @@ -/* -================================================================================ -C++ Primer 5th Exercise Answer Source Code -Copyright (C) 2014-2015 github.com/pezy/CppPrimer - -Write a template that acts like the library `find` algorithm. - -If you have questions, try to connect with me: pezy -================================================================================ -*/ - #ifndef CP5_EX16_04_FIND_H_ #define CP5_EX16_04_FIND_H_ diff --git a/ch16/ex16_05_print_array.h b/ch16/ex16_05_print_array.h index 3aa78084..c584a504 100644 --- a/ch16/ex16_05_print_array.h +++ b/ch16/ex16_05_print_array.h @@ -1,16 +1,3 @@ -/* -================================================================================ -C++ Primer 5th Exercise Answer Source Code -Copyright (C) 2014-2015 github.com/pezy/CppPrimer - -Write a template version of the `print` function from 6.2.4 (p. 217) -that takes a reference to an array and can handle arrays of any size -and any element type. - -If you have questions, try to connect with me: pezy -================================================================================ -*/ - #ifndef CP5_EX16_05_PRINT_ARRAY_H_ #define CP5_EX16_05_PRINT_ARRAY_H_ diff --git a/ch16/ex16_06_begin_end.h b/ch16/ex16_06_begin_end.h index 97acb1f7..1483e355 100644 --- a/ch16/ex16_06_begin_end.h +++ b/ch16/ex16_06_begin_end.h @@ -1,15 +1,3 @@ -/* -================================================================================ -C++ Primer 5th Exercise Answer Source Code -Copyright (C) 2014-2015 github.com/pezy/CppPrimer - -Define your own versions of `begin` and `end` functions that take an array -argument work. - -If you have questions, try to connect with me: pezy -================================================================================ -*/ - #ifndef CP5_EX16_06_BEGIN_END_H_ #define CP5_EX16_06_BEGIN_END_H_ diff --git a/ch16/ex16_07_sizeof_array.h b/ch16/ex16_07_sizeof_array.h index 5c2d02c7..beffc55e 100644 --- a/ch16/ex16_07_sizeof_array.h +++ b/ch16/ex16_07_sizeof_array.h @@ -1,14 +1,3 @@ -/* -================================================================================ -C++ Primer 5th Exercise Answer Source Code -Copyright (C) 2014-2015 github.com/pezy/CppPrimer - -a `constexpr` template that returns the size of a given array. - -If you have questions, try to connect with me: pezy -================================================================================ -*/ - #ifndef CP5_EX16_07_SIZEOF_ARRAY_H_ #define CP5_EX16_07_SIZEOF_ARRAY_H_ diff --git a/ch16/ex16_12_blob.h b/ch16/ex16_12_blob.h index 5346e1ca..4faf97a7 100644 --- a/ch16/ex16_12_blob.h +++ b/ch16/ex16_12_blob.h @@ -1,14 +1,3 @@ -/* -================================================================================ -C++ Primer 5th Exercise Answer Source Code -Copyright (C) 2014-2015 github.com/pezy/CppPrimer - -own version of the `Blob`. - -If you have questions, try to connect with me: pezy -================================================================================ -*/ - #ifndef CP5_EX16_12_BLOB_H_ #define CP5_EX16_12_BLOB_H_ diff --git a/ch16/ex16_14_screen.h b/ch16/ex16_14_screen.h index f2a24ee5..24df46ac 100644 --- a/ch16/ex16_14_screen.h +++ b/ch16/ex16_14_screen.h @@ -1,15 +1,3 @@ -/* -================================================================================ -C++ Primer 5th Exercise Answer Source Code -Copyright (C) 2014-2015 github.com/pezy/CppPrimer - -a `Screen` class template that uses nontype parameters to define the height and -width of the `Screen`. - -If you have questions, try to connect with me: pezy -================================================================================ -*/ - #ifndef CP5_EX16_14_SCREEN_H_ #define CP5_EX16_14_SCREEN_H_ diff --git a/ch16/ex16_16_vec.h b/ch16/ex16_16_vec.h index d3aef071..6b1573cf 100644 --- a/ch16/ex16_16_vec.h +++ b/ch16/ex16_16_vec.h @@ -1,14 +1,3 @@ -/* -================================================================================ -C++ Primer 5th Exercise Answer Source Code -Copyright (C) 2014-2015 github.com/pezy/CppPrimer - -Rewrite the `Vec` class (§ 13.5, p. 526) as a template named `Vec` - -If you have questions, try to connect with me: pezy -================================================================================ -*/ - #ifndef CP5_EX16_16_VEC_H_ #define CP5_EX16_16_VEC_H_ diff --git a/ch16/ex16_19_print_container.cpp b/ch16/ex16_19_print_container.cpp new file mode 100644 index 00000000..706abece --- /dev/null +++ b/ch16/ex16_19_print_container.cpp @@ -0,0 +1,18 @@ +#include +#include + +template +std::ostream& print(const Container& c, std::ostream& os = std::cout) +{ + using size_type = typename Container::size_type; + for (size_type i = 0; i != c.size(); ++i) { + os << c.at(i) << " "; + } + return os; +} + +int main() +{ + std::vector vec{2, 4, 6, 8, 7, 5, 3, 1}; + print(vec) << "\n"; +} \ No newline at end of file diff --git a/ch16/ex16_20_print_container_iter.cpp b/ch16/ex16_20_print_container_iter.cpp new file mode 100644 index 00000000..404178f5 --- /dev/null +++ b/ch16/ex16_20_print_container_iter.cpp @@ -0,0 +1,17 @@ +#include +#include + +template +std::ostream& print(const Container& c, std::ostream& os = std::cout) +{ + for (auto iter = c.begin(); iter != c.end(); ++iter) { + os << *iter << " "; + } + return os; +} + +int main() +{ + std::vector vec{2, 4, 6, 8, 7, 5, 3, 1}; + print(vec) << "\n"; +} \ No newline at end of file diff --git a/ch16/ex16_21_debugdelete.cpp b/ch16/ex16_21_debugdelete.cpp new file mode 100644 index 00000000..3e5f4b65 --- /dev/null +++ b/ch16/ex16_21_debugdelete.cpp @@ -0,0 +1,18 @@ +#include "ex16_21_debugdelete.h" +#include +#include + +using std::string; + +int main() +{ + double* p = new double(8.0); + DebugDelete d; + d(p); + + int* ip = new int; + DebugDelete()(ip); + + std::unique_ptr up(new int, DebugDelete()); + std::unique_ptr usp(new string, DebugDelete()); +} \ No newline at end of file diff --git a/ch16/ex16_21_debugdelete.h b/ch16/ex16_21_debugdelete.h new file mode 100644 index 00000000..17108d8c --- /dev/null +++ b/ch16/ex16_21_debugdelete.h @@ -0,0 +1,20 @@ +#ifndef CP5_EX16_21_DEBUGDELETE_H_ +#define CP5_EX16_21_DEBUGDELETE_H_ + +#include + +class DebugDelete { +public: + DebugDelete(std::ostream& os = std::cerr) : os_(os) {} + + template void operator()(T* p) const + { + os_ << "deleting unique_ptr by '" << __PRETTY_FUNCTION__ << "'\n"; + delete p; + } + +private: + std::ostream& os_; +}; + +#endif // CP5_EX16_21_DEBUGDELETE_H_ \ No newline at end of file diff --git a/ch16/ex16_22_textquery.cpp b/ch16/ex16_22_textquery.cpp new file mode 100644 index 00000000..fe086c72 --- /dev/null +++ b/ch16/ex16_22_textquery.cpp @@ -0,0 +1,45 @@ +#include "ex16_22_textquery.h" +#include "ex16_21_debugdelete.h" +#include +#include +#include + +TextQuery::TextQuery(std::ifstream& ifs) + : input(new vector, DebugDelete()) +{ + LineNo lineNo{0}; + for (string line; std::getline(ifs, line); ++lineNo) { + input->push_back(line); + std::istringstream line_stream(line); + for (string text, word; line_stream >> text; word.clear()) { + // avoid read a word followed by punctuation(such as: word, ) + std::remove_copy_if(text.begin(), text.end(), + std::back_inserter(word), ispunct); + // use reference avoid count of shared_ptr add. + auto& nos = result[word]; + if (!nos) nos.reset(new std::set, DebugDelete()); + nos->insert(lineNo); + } + } +} + +QueryResult TextQuery::query(const string& str) const +{ + // use static just allocate once. + static shared_ptr> nodate(new std::set, + DebugDelete()); + auto found = result.find(str); + if (found == result.end()) + return QueryResult(str, nodate, input); + else + return QueryResult(str, found->second, input); +} + +std::ostream& print(std::ostream& out, const QueryResult& qr) +{ + out << qr.word << " occurs " << qr.nos->size() + << (qr.nos->size() > 1 ? " times" : " time") << std::endl; + for (auto i : *qr.nos) + out << "\t(line " << i + 1 << ") " << qr.input->at(i) << std::endl; + return out; +} diff --git a/ch16/ex16_22_textquery.h b/ch16/ex16_22_textquery.h new file mode 100644 index 00000000..e612f885 --- /dev/null +++ b/ch16/ex16_22_textquery.h @@ -0,0 +1,49 @@ +#ifndef CP5_EX16_22_TEXTQUERY_H_ +#define CP5_EX16_22_TEXTQUERY_H_ + +#include +using std::string; + +#include +using std::vector; + +#include +using std::shared_ptr; + +#include +#include +#include +#include + +class QueryResult; +class TextQuery { +public: + using LineNo = vector::size_type; + TextQuery(std::ifstream&); + QueryResult query(const string&) const; + +private: + shared_ptr> input; + std::map>> result; +}; + +class QueryResult { +public: + friend std::ostream& print(std::ostream&, const QueryResult&); + +public: + QueryResult(const string& s, shared_ptr> set, + shared_ptr> v) + : word(s), nos(set), input(v) + { + } + +private: + string word; + shared_ptr> nos; + shared_ptr> input; +}; + +std::ostream& print(std::ostream&, const QueryResult&); + +#endif // CP5_EX16_22_TEXTQUERY_H_ \ No newline at end of file diff --git a/ch16/ex16_22_textquery_test.cpp b/ch16/ex16_22_textquery_test.cpp new file mode 100644 index 00000000..3f9b79ed --- /dev/null +++ b/ch16/ex16_22_textquery_test.cpp @@ -0,0 +1,19 @@ +#include "ex16_22_textquery.h" +#include + +void runQueries(std::ifstream& infile) +{ + TextQuery tq(infile); + while (true) { + std::cout << "enter word to look for, or q to quit: "; + string s; + if (!(std::cin >> s) || s == "q") break; + print(std::cout, tq.query(s)) << std::endl; + } +} + +int main() +{ + std::ifstream file("../data/storyDataFile.txt"); + runQueries(file); +} diff --git a/ch16/ex16_24_blob.h b/ch16/ex16_24_blob.h new file mode 100644 index 00000000..1ee4476e --- /dev/null +++ b/ch16/ex16_24_blob.h @@ -0,0 +1,455 @@ +#ifndef CP5_EX16_24_BLOB_H_ +#define CP5_EX16_24_BLOB_H_ + +#include +using std::vector; + +#include +using std::initializer_list; + +#include +using std::make_shared; +using std::shared_ptr; + +#include +#include + +#ifndef _MSC_VER +#define NOEXCEPT noexcept +#else +#define NOEXCEPT +#endif + +template class BlobPtr; +template class ConstBlobPtr; +template class Blob; + +//============================================================================== +// Blob - custom vector. +//============================================================================== + +template class Blob { + friend class ConstBlobPtr; + friend class BlobPtr; + friend bool operator==(const Blob& lhs, const Blob& rhs) { return *lhs.data == *rhs.data; } + friend bool operator!=(const Blob& lhs, const Blob& rhs) { return !(lhs == rhs); } + friend bool operator<(const Blob& lhs, const Blob& rhs) + { + return std::lexicographical_compare(lhs.data->begin(), lhs.data->end(), rhs.data->begin(), + rhs.data->end()); + } + friend bool operator>(const Blob& lhs, const Blob& rhs) { return rhs < lhs; } + friend bool operator<=(const Blob& lhs, const Blob& rhs) { return !(rhs < lhs); } + friend bool operator>=(const Blob& lhs, const Blob& rhs) { return !(lhs < rhs); } + +public: + using size_type = typename vector::size_type; + + Blob() : data(make_shared>()) {} + Blob(initializer_list il) : data(make_shared>(il)) {} + template Blob(It b, It e) : data(make_shared>(b, e)) {} + + Blob(const Blob& b) : data(make_shared>(*b.data)) {} + Blob& operator=(const Blob& b); + + Blob(Blob&& b) NOEXCEPT : data(std::move(b.data)) {} + Blob& operator=(Blob&& b) NOEXCEPT; + + BlobPtr begin(); + BlobPtr end(); + + ConstBlobPtr cbegin() const; + ConstBlobPtr cend() const; + + T& operator[](size_t n); + const T& operator[](size_t n) const; + + size_type size() const { return data->size(); } + bool empty() const { return data->empty(); } + + void push_back(const T& t) { data->push_back(t); } + void push_back(T&& s) { data->push_back(std::move(s)); } + + void pop_back(); + T& front(); + T& back(); + const T& front() const; + const T& back() const; + +private: + void check(size_type, const T&) const; + + shared_ptr> data; +}; + +//------------------------------------------------------------------------------ +// member function. +//------------------------------------------------------------------------------ + +template Blob& Blob::operator=(const Blob& b) +{ + data = make_shared>(*b.data); + return *this; +} + +template Blob& Blob::operator=(Blob&& b) NOEXCEPT +{ + if (this != &b) { + data = std::move(b.data); + b.data = nullptr; + } + + return *this; +} + +template BlobPtr Blob::begin() +{ + return BlobPtr(*this); +} + +template BlobPtr Blob::end() +{ + return BlobPtr(*this, data->size()); +} + +template ConstBlobPtr Blob::cbegin() const +{ + return ConstBlobPtr(*this); +} + +template ConstBlobPtr Blob::cend() const +{ + return ConstBlobPtr(*this, data->size()); +} + +template inline void Blob::pop_back() +{ + check(0, "pop_back on empty Blob"); + data->pop_back(); +} + +template inline T& Blob::front() +{ + check(0, "front on empty Blob"); + return data->front(); +} + +template inline T& Blob::back() +{ + check(0, "back on empty Blob"); + return data->back(); +} + +template inline const T& Blob::front() const +{ + check(0, "front on empty Blob"); + return data->front(); +} + +template inline const T& Blob::back() const +{ + check(0, "back on empty Blob"); + return data->back(); +} + +template inline void Blob::check(size_type i, const T& msg) const +{ + if (i >= data->size()) throw std::out_of_range(msg); +} + +template inline T& Blob::operator[](size_t n) +{ + check(n, "out of range"); + return data->at(n); +} + +template inline const T& Blob::operator[](size_t n) const +{ + check(n, "out of range"); + return data->at(n); +} + +//================================================================================= +// BlobPtr - custom iterator of Blob +//================================================================================= + +template class BlobPtr { + friend bool operator==(const BlobPtr& lhs, const BlobPtr& rhs) + { + return lhs.curr == rhs.curr; + } + friend bool operator!=(const BlobPtr& lhs, const BlobPtr& rhs) { return !(lhs == rhs); } + friend bool operator<(const BlobPtr& lhs, const BlobPtr& rhs) + { + return lhs.curr < rhs.curr; + } + friend bool operator>(const BlobPtr& lhs, const BlobPtr& rhs) + { + return lhs.curr > rhs.curr; + } + friend bool operator<=(const BlobPtr& lhs, const BlobPtr& rhs) + { + return lhs.curr <= rhs.curr; + } + friend bool operator>=(const BlobPtr& lhs, const BlobPtr& rhs) + { + return lhs.curr >= rhs.curr; + } + +public: + BlobPtr() : curr(0) {} + BlobPtr(Blob& s, size_t sz = 0) : wptr(s.data), curr(sz) {} + + T& operator*() const; + T* operator->() const; + BlobPtr& operator++(); + BlobPtr& operator--(); + BlobPtr operator++(int); + BlobPtr operator--(int); + BlobPtr& operator+=(size_t); + BlobPtr& operator-=(size_t); + BlobPtr operator+(size_t) const; + BlobPtr operator-(size_t) const; + + T& operator[](size_t n); + const T& operator[](size_t n) const; + +private: + shared_ptr> check(size_t, const T&) const; + + std::weak_ptr> wptr; + size_t curr; +}; + +//------------------------------------------------------------------------------ +// member function. +//------------------------------------------------------------------------------ + +template T& BlobPtr::operator*() const +{ + auto p = check(curr, "dereference past end"); + return (*p)[curr]; +} + +template T* BlobPtr::operator->() const +{ + return &this->operator*(); +} + +template inline BlobPtr& BlobPtr::operator++() +{ + check(curr, "increment past end of BlobPtr"); + ++curr; + return *this; +} + +template inline BlobPtr& BlobPtr::operator--() +{ + --curr; + check(-1, "decrement past begin of BlobPtr"); + return *this; +} + +template inline BlobPtr BlobPtr::operator++(int) +{ + BlobPtr ret = *this; + ++*this; + return ret; +} + +template inline BlobPtr BlobPtr::operator--(int) +{ + BlobPtr ret = *this; + --*this; + return ret; +} + +template inline BlobPtr& BlobPtr::operator+=(size_t n) +{ + curr += n; + check(curr, "increment past end of BlobPtr"); + return *this; +} + +template inline BlobPtr& BlobPtr::operator-=(size_t n) +{ + curr -= n; + check(curr, "increment past end of BlobPtr"); + return *this; +} + +template inline BlobPtr BlobPtr::operator+(size_t n) const +{ + BlobPtr ret = *this; + ret += n; + return ret; +} + +template inline BlobPtr BlobPtr::operator-(size_t n) const +{ + BlobPtr ret = *this; + ret -= n; + return ret; +} + +template inline shared_ptr> BlobPtr::check(size_t i, const T& msg) const +{ + auto ret = wptr.lock(); + if (!ret) throw std::runtime_error("unbound BlobPtr"); + if (i >= ret->size()) throw std::out_of_range(msg); + return ret; +} + +template inline T& BlobPtr::operator[](size_t n) +{ + auto p = check(n, "dereference out of range."); + return (*p)[n]; +} + +template inline const T& BlobPtr::operator[](size_t n) const +{ + auto p = check(n, "dereference out of range."); + return (*p)[n]; +} + +//================================================================================= +// ConstBlobPtr - custom const_iterator of Blob +//================================================================================= + +template class ConstBlobPtr { + friend bool operator==(const ConstBlobPtr& lhs, const ConstBlobPtr& rhs) + { + return lhs.curr == rhs.curr; + } + friend bool operator!=(const ConstBlobPtr& lhs, const ConstBlobPtr& rhs) + { + return !(lhs == rhs); + } + friend bool operator<(const ConstBlobPtr& lhs, const ConstBlobPtr& rhs) + { + return lhs.curr < rhs.curr; + } + friend bool operator>(const ConstBlobPtr& lhs, const ConstBlobPtr& rhs) + { + return lhs.curr > rhs.curr; + } + friend bool operator<=(const ConstBlobPtr& lhs, const ConstBlobPtr& rhs) + { + return lhs.curr <= rhs.curr; + } + friend bool operator>=(const ConstBlobPtr& lhs, const ConstBlobPtr& rhs) + { + return lhs.curr >= rhs.curr; + } + +public: + ConstBlobPtr() : curr(0) {} + ConstBlobPtr(const Blob& s, size_t sz = 0) : wptr(s.data), curr(sz) {} + + const T& operator*() const; + const T* operator->() const; + ConstBlobPtr& operator++(); + ConstBlobPtr& operator--(); + ConstBlobPtr operator++(int); + ConstBlobPtr operator--(int); + ConstBlobPtr& operator+=(size_t); + ConstBlobPtr& operator-=(size_t); + ConstBlobPtr operator+(size_t) const; + ConstBlobPtr operator-(size_t) const; + + const T& operator[](size_t n) const; + +private: + std::shared_ptr> check(size_t, const T&) const; + + std::weak_ptr> wptr; + size_t curr; +}; + +//------------------------------------------------------------------------------ +// member function. +//------------------------------------------------------------------------------ + +template inline const T& ConstBlobPtr::operator*() const +{ + auto p = check(curr, "dereference past end"); + return (*p)[curr]; +} + +template inline const T* ConstBlobPtr::operator->() const +{ + return &this->operator*(); +} + +template inline ConstBlobPtr& ConstBlobPtr::operator++() +{ + check(curr, "increment past end of ConstBlobPtr"); + ++curr; + return *this; +} + +template inline ConstBlobPtr& ConstBlobPtr::operator--() +{ + --curr; + check(-1, "decrement past begin of ConstBlobPtr"); + return *this; +} + +template inline ConstBlobPtr ConstBlobPtr::operator++(int) +{ + ConstBlobPtr ret = *this; + ++*this; + return ret; +} + +template inline ConstBlobPtr ConstBlobPtr::operator--(int) +{ + ConstBlobPtr ret = *this; + --*this; + return ret; +} + +template inline ConstBlobPtr& ConstBlobPtr::operator+=(size_t n) +{ + curr += n; + check(curr, "increment past end of ConstBlobPtr"); + return *this; +} + +template inline ConstBlobPtr& ConstBlobPtr::operator-=(size_t n) +{ + curr -= n; + check(curr, "increment past end of ConstBlobPtr"); + return *this; +} + +template inline ConstBlobPtr ConstBlobPtr::operator+(size_t n) const +{ + ConstBlobPtr ret = *this; + ret += n; + return ret; +} + +template inline ConstBlobPtr ConstBlobPtr::operator-(size_t n) const +{ + ConstBlobPtr ret = *this; + ret -= n; + return ret; +} + +template +inline std::shared_ptr> ConstBlobPtr::check(size_t i, const T& msg) const +{ + auto ret = wptr.lock(); + if (!ret) throw std::runtime_error("unbound BlobPtr"); + if (i >= ret->size()) throw std::out_of_range(msg); + return ret; +} + +template inline const T& ConstBlobPtr::operator[](size_t n) const +{ + auto p = check(n, "dereference out of range."); + return (*p)[n]; +} + +#endif // CP5_EX16_24_BLOB_H_ diff --git a/ch16/ex16_24_blob_test.cpp b/ch16/ex16_24_blob_test.cpp new file mode 100644 index 00000000..737ab482 --- /dev/null +++ b/ch16/ex16_24_blob_test.cpp @@ -0,0 +1,29 @@ +#include "ex16_24_blob.h" +#include +#include + +int main() +{ + Blob sb1{"a", "b", "c"}; + Blob sb2 = sb1; + + sb2[2] = "b"; + + if (sb1 > sb2) { + for (auto iter = sb2.cbegin(); iter != sb2.cend(); ++iter) { + std::cout << *iter << " "; + } + std::cout << std::endl; + } + + ConstBlobPtr iter(sb2); + std::cout << iter->size() << std::endl; + + std::vector vec{"good", "for", "you"}; + Blob sb3(vec.begin(), vec.end()); + + for (auto&& s : sb3) { + std::cout << s << " "; + } + std::cout << "\n"; +} From f9fa588a1086facfbf2fb44223e55591a78ee49b Mon Sep 17 00:00:00 2001 From: pezy Date: Thu, 12 Apr 2018 00:40:34 +0800 Subject: [PATCH 02/11] added 16_28. --- ch16/README.md | 2 ++ ch16/ex16_28_shared_ptr.h | 65 +++++++++++++++++++++++++++++++++++++++ ch16/ex16_28_test.cpp | 40 ++++++++++++++++++++++++ ch16/ex16_28_unique_ptr.h | 0 4 files changed, 107 insertions(+) create mode 100644 ch16/ex16_28_shared_ptr.h create mode 100644 ch16/ex16_28_test.cpp create mode 100644 ch16/ex16_28_unique_ptr.h diff --git a/ch16/README.md b/ch16/README.md index 0f3d5421..649d894a 100644 --- a/ch16/README.md +++ b/ch16/README.md @@ -237,6 +237,8 @@ Solution from [How is a template instantiated? - Stack Overflow](https://stackov > Write your own versions of `shared_ptr` and `unique_ptr`. +[shared_ptr](ex16_28_shared_ptr.h) | [unique_ptr](ex16_28_unique_ptr.h) | [test](ex16_28_test.cpp) + ## Exercise 16.29 > Revise your `Blob` class to use your version of `shared_ptr` rather than the library version. diff --git a/ch16/ex16_28_shared_ptr.h b/ch16/ex16_28_shared_ptr.h new file mode 100644 index 00000000..2dcb4561 --- /dev/null +++ b/ch16/ex16_28_shared_ptr.h @@ -0,0 +1,65 @@ +#ifndef CP5_EX16_28_SHARED_PTR_H_ +#define CP5_EX16_28_SHARED_PTR_H_ + +#include "ex16_21_debugdelete.h" +#include + +template class SharedPtr { +public: + friend void swap(SharedPtr& lhs, SharedPtr& rhs) + { + using std::swap; + swap(lhs.ptr_, rhs.ptr_); + swap(lhs.count_ptr_, rhs.count_ptr_); + swap(lhs.delete_, rhs.deleter_); + } + + SharedPtr(T* ptr = nullptr, const std::function& del = DebugDelete()) + : ptr_(ptr), count_ptr_(new size_t(ptr != nullptr)), deleter_(del) + { + } + + ~SharedPtr() + { + if (!ptr_) return; + if (--*count_ptr_ == 0) { + deleter_(ptr_); + delete count_ptr_; + } + ptr_ = nullptr; + count_ptr_ = nullptr; + } + + SharedPtr(const SharedPtr& sp) : ptr_(sp.ptr_), count_ptr_(sp.count_ptr_), deleter_(sp.deleter_) + { + ++*count_ptr_; + } + + SharedPtr& operator=(SharedPtr sp) + { + swap(*this, sp); + return *this; + } + + SharedPtr(const SharedPtr&& sp) noexcept : SharedPtr() { swap(*this, sp); } + + void reset(T* ptr = nullptr, const std::function& del = DebugDelete()) + { + swap(*this, SharePtr(ptr, del)); + } + + void swap(SharedPtr& r) noexcept { swap(*this, r); } + + T* get() const noexcept { return ptr_; } + T& operator*() const noexcept { return *get(); } + T* operator->() const noexcept { return get(); } + size_t use_count() const noexcept { return *count_ptr_; } + explicit operator bool() const noexcept { return ptr_ != nullptr; } + +private: + T* ptr_ = nullptr; + size_t* count_ptr_ = nullptr; + std::function deleter_; +}; + +#endif // CP5_EX16_28_SHARED_PTR_H_ \ No newline at end of file diff --git a/ch16/ex16_28_test.cpp b/ch16/ex16_28_test.cpp new file mode 100644 index 00000000..10f48766 --- /dev/null +++ b/ch16/ex16_28_test.cpp @@ -0,0 +1,40 @@ +#include "ex16_28_shared_ptr.h" +#include + +struct Foo { + Foo() { std::cout << "Foo()\n"; } + ~Foo() { std::cout << "~Foo()\n"; } +}; + +struct D { + void operator()(Foo* p) const + { + std::cout << "Call delete from function object...\n"; + delete p; + } +}; + +int main() +{ + { + std::cout << "constructor with no managed object\n"; + SharedPtr sh1; + } + + { + std::cout << "constructor with object\n"; + SharedPtr sh2(new Foo); + SharedPtr sh3(sh2); + std::cout << sh2.use_count() << '\n'; + std::cout << sh3.use_count() << '\n'; + } + + { + std::cout << "constructor with object and deleter\n"; + SharedPtr sh4(new Foo, D()); + SharedPtr sh5(new Foo, [](Foo* p) { + std::cout << "Call delete from lambda...\n"; + delete p; + }); + } +} \ No newline at end of file diff --git a/ch16/ex16_28_unique_ptr.h b/ch16/ex16_28_unique_ptr.h new file mode 100644 index 00000000..e69de29b From 73c5cd3e1a826c03a57fbe1356b2835dd70e488f Mon Sep 17 00:00:00 2001 From: pezy Date: Wed, 18 Apr 2018 00:01:25 +0800 Subject: [PATCH 03/11] finished 16.28 --- ch16/ex16.28/DebugDelete.h | 31 ----- ch16/ex16.28/main.cpp | 36 ------ ch16/ex16.28/shared_pointer.h | 219 ---------------------------------- ch16/ex16.28/unique_pointer.h | 117 ------------------ ch16/ex16_28_shared_ptr.h | 40 +++---- ch16/ex16_28_test.cpp | 65 +++++++++- ch16/ex16_28_unique_ptr.h | 72 +++++++++++ 7 files changed, 151 insertions(+), 429 deletions(-) delete mode 100644 ch16/ex16.28/DebugDelete.h delete mode 100644 ch16/ex16.28/main.cpp delete mode 100644 ch16/ex16.28/shared_pointer.h delete mode 100644 ch16/ex16.28/unique_pointer.h diff --git a/ch16/ex16.28/DebugDelete.h b/ch16/ex16.28/DebugDelete.h deleted file mode 100644 index 923dccbe..00000000 --- a/ch16/ex16.28/DebugDelete.h +++ /dev/null @@ -1,31 +0,0 @@ -/*************************************************************************** - * @file DebugDelete.h - * @author Alan.W - * @date 04 Feb 2014 - * @remark This code is for the exercises from C++ Primer 5th Edition - * @note - ***************************************************************************/ - -#ifndef DEBUGDELETE_H -#define DEBUGDELETE_H - -#include - -/** - * @brief The DebugDelete class is a deleter functor using delete - */ -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 // DEBUGDELETE_H diff --git a/ch16/ex16.28/main.cpp b/ch16/ex16.28/main.cpp deleted file mode 100644 index cc221f5c..00000000 --- a/ch16/ex16.28/main.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/*************************************************************************** - * @file main.cpp - * @author Alan.W - * @date 04 Feb 2014 - * @remark This code is for the exercises from C++ Primer 5th Edition - * @note - ***************************************************************************/ -//! -//! Exercise 16.28 Write your own versions of shared_ptr and unique_ptr -//! - - -#include -#include -#include -#include -#include "DebugDelete.h" -#include "shared_pointer.h" -#include "unique_pointer.h" - - - - -int main() -{ - std::vector> v; - - for(int u = 0; u !=10 ; ++u) - v.push_back(unique_pointer(new int(u))); - - for(auto& sp : v) - std::cout << *sp << "\n"; - - -} - diff --git a/ch16/ex16.28/shared_pointer.h b/ch16/ex16.28/shared_pointer.h deleted file mode 100644 index 79818f7b..00000000 --- a/ch16/ex16.28/shared_pointer.h +++ /dev/null @@ -1,219 +0,0 @@ -/*************************************************************************** - * @file shared_pointer.h - * @author Alan.W - * @date 04 Feb 2014 - * @remark This code is for the exercises from C++ Primer 5th Edition - * @note - ***************************************************************************/ -#ifndef SHARED_POINTER_H -#define SHARED_POINTER_H - -#include "DebugDelete.h" -#include - -//! forward declarations needed for friendship - -template class shared_pointer; - -template void swap(shared_pointer& lhs, shared_pointer& rhs); - - -/** - * @brief shared_ptr like template class - * @note don't mix this one with std::shared_ptr. - * DebugDelete is the default deleter which can be replaced at run time - */ -template -class shared_pointer -{ - friend void swap(shared_pointer& lhs, shared_pointer& rhs); - //! ^^^ -- don't forget this. - -public: - - //! default constructor - shared_pointer() = default; - - //! constructor taking raw pointer. - //! set the refCount as 1 - explicit shared_pointer(T* up, std::function d = DebugDelete()) : - ptr(up), refCount(new std::size_t(1)), deleter(d) { } - - //! copy constructor. - //! increment useCount for each Copy - shared_pointer(const shared_pointer& sp): - ptr(sp.ptr), refCount(sp.refCount), deleter(sp.deleter) - { ++*refCount; } - - //! move constructor - shared_pointer(shared_pointer&& sp) noexcept; - - //! copy assignment - shared_pointer& operator =(const shared_pointer& rhs); - - //! move assignment - shared_pointer& operator =(shared_pointer&& rhs) noexcept; - - - - - //! conversion operator - operator bool() const { return ptr ? true : false;} - - //! dereference - T& operator* () const { return *ptr; } - - //! arrow - T* operator->() const { return & this->operator *(); } - - //! return useCount - std::size_t use_count() const { return *refCount; } - - //! get the underlying pointer - T* get() const noexcept { return ptr; } - - //! check if the unique user - bool unique() const noexcept { return *refCount == 1;} - - //! swap - void swap( shared_pointer& rhs) { ::swap(*this, rhs); } - - //! if unique user, free the object pointed to - void reset() noexcept { decrement_n_destroy(); } - - //! make prt point where p pointing and create a new coount for it - void reset(T* p) - { - if(ptr != p) - { - decrement_n_destroy(); - ptr = p; - refCount = new std::size_t(1); - } - } - - //! reset to point where p is pointing and change deleter to d. - void reset(T *p, const std::function& d) - { - reset(p); - deleter = d; - } - - - - - //! destructor - ~shared_pointer() - { - decrement_n_destroy(); - } -private: - - //! data structure - T* ptr = nullptr; - std::size_t* refCount = new std::size_t(0); - - //! any functor lambda or function pointer that matched this - //! signature can replace the default one at run time. - std::function deleter{DebugDelete()}; - //! signature ^^^^^^^^ ^~~~~~~~~~~~~~^ - //! here: = doesn't work, another way is initializing it in constructor. - - //! utilities - void decrement_n_destroy(); - -}; - - - -/** - * @brief swap and big 5 - */ -template -inline void -swap(shared_pointer& lhs, shared_pointer& rhs) -{ - using std::swap; - swap(lhs.ptr, rhs.ptr); - swap(lhs.refCount, rhs.refCount); - swap(lhs.deleter, rhs.deleter); -} - - -//! move constructor -template -inline -shared_pointer::shared_pointer(shared_pointer&& sp) noexcept: - ptr(sp.ptr), refCount(sp.refCount), deleter(std::move(sp.deleter)) -{ - sp.ptr = nullptr; - sp.refCount = nullptr; -} - -//! copy assignment -template -inline shared_pointer& -shared_pointer::operator =(const shared_pointer& rhs) -{ - //! increment rhs.refCount first to ensure safty when self-assignment - ++*rhs.refCount; - - //! for lhs: - decrement_n_destroy(); - - //! copy datastructure from rhs to this. - ptr = rhs.ptr; - refCount = rhs.refCount; - deleter = rhs.deleter; - - return *this; -} - - -//! move assignment -template -inline shared_pointer& -shared_pointer::operator =(shared_pointer&& rhs) noexcept -{ - //! for lhs - decrement_n_destroy(); - - //! swap two sides - ::swap(*this, rhs); - - std::cout << "shared_pointer::move=\n"; - - return *this; -} - -/** - *@brief operators: - **/ - -template -inline std::ostream& -operator <<(std::ostream& os, shared_pointer p) -{ - os << p.get(); - return os; -} - - -//! utilities for decrement and delete using deleter. -template -inline void -shared_pointer::decrement_n_destroy() -{ - if(ptr) - { - if (--*refCount == 0) - { - delete refCount; - deleter(ptr); - } - refCount = nullptr; - ptr = nullptr; - } -} - -#endif // SHARED_POINTER_H diff --git a/ch16/ex16.28/unique_pointer.h b/ch16/ex16.28/unique_pointer.h deleted file mode 100644 index 8a49e2c7..00000000 --- a/ch16/ex16.28/unique_pointer.h +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef UNIQUE_POINTER_H -#define UNIQUE_POINTER_H - -#include - -//! forward declarations for friendship - -template class unique_pointer; -template void - swap(unique_pointer& lhs, unique_pointer& rhs); - -/** - * @brief std::unique_ptr like class template. - */ -template -class unique_pointer -{ - friend void swap(unique_pointer& lhs, unique_pointer& rhs); - -public: - //! preventing copy and assignment - unique_pointer(const unique_pointer&) = delete; - unique_pointer& operator = (const unique_pointer&) = delete; - - //! default constructor and one taking T* - unique_pointer() = default; - explicit unique_pointer(T* up): ptr(up) { } - - //! move constructor - unique_pointer(unique_pointer&& up) noexcept - : ptr(up.ptr) { up.ptr = nullptr; } - - //! move assignment - unique_pointer& operator =(unique_pointer&& rhs) noexcept; - - //! std::nullptr_t assignment - unique_pointer& operator =(std::nullptr_t n) noexcept; - - - - //! operator overloaded : * -> bool - T& operator *() const { return *ptr; } - T* operator ->() const { return & this->operator *(); } - operator bool() const { return ptr ? true : false; } - - //! return the underlying pointer - T* get() const noexcept { return ptr;} - - //! swap member using swap friend - void swap(unique_pointer &rhs) {::swap(*this, rhs);} - - //! free and make it point to nullptr or to p's pointee. - void reset() noexcept { deleter(ptr); ptr = nullptr; } - void reset(T* p) noexcept { deleter(ptr); ptr = p; } - - //! return ptr and make ptr point to nullptr. - T* release(); - - - ~unique_pointer() - { - deleter(ptr); - } -private: - T* ptr = nullptr; - D deleter = D(); -}; - - -//! swap -template -inline void -swap(unique_pointer& lhs, unique_pointer& rhs) -{ - using std::swap; - swap(lhs.ptr, rhs.ptr); - swap(lhs.deleter, rhs.deleter); -} - -//! move assignment -template -inline unique_pointer& -unique_pointer::operator =(unique_pointer&& rhs) noexcept -{ - //! prevent self-assignment - if(this->ptr != rhs.ptr) - { - deleter(ptr); - ptr = nullptr; - ::swap(*this, rhs); - } - return *this; -} - - -//! std::nullptr_t assignment -template -inline unique_pointer& -unique_pointer::operator =(std::nullptr_t n) noexcept -{ - if(n == nullptr) - { - deleter(ptr); ptr = nullptr; - } - return *this; -} - - //! relinquish contrul by returnning ptr and making ptr point to nullptr. -template -inline T* -unique_pointer::release() -{ - T* ret = ptr; - ptr = nullptr; - return ret; -} -#endif // UNIQUE_POINTER_H diff --git a/ch16/ex16_28_shared_ptr.h b/ch16/ex16_28_shared_ptr.h index 2dcb4561..22e1ba55 100644 --- a/ch16/ex16_28_shared_ptr.h +++ b/ch16/ex16_28_shared_ptr.h @@ -1,21 +1,12 @@ #ifndef CP5_EX16_28_SHARED_PTR_H_ #define CP5_EX16_28_SHARED_PTR_H_ -#include "ex16_21_debugdelete.h" -#include - template class SharedPtr { -public: - friend void swap(SharedPtr& lhs, SharedPtr& rhs) - { - using std::swap; - swap(lhs.ptr_, rhs.ptr_); - swap(lhs.count_ptr_, rhs.count_ptr_); - swap(lhs.delete_, rhs.deleter_); - } + using DelFuncPtr = void (*)(T*); - SharedPtr(T* ptr = nullptr, const std::function& del = DebugDelete()) - : ptr_(ptr), count_ptr_(new size_t(ptr != nullptr)), deleter_(del) +public: + SharedPtr(T* ptr = nullptr, DelFuncPtr del = nullptr) + : ptr_(ptr), count_ptr_(new size_t(ptr != nullptr)), del_(del) { } @@ -23,32 +14,39 @@ template class SharedPtr { { if (!ptr_) return; if (--*count_ptr_ == 0) { - deleter_(ptr_); + del_ ? del_(ptr_) : delete ptr_; delete count_ptr_; } ptr_ = nullptr; count_ptr_ = nullptr; } - SharedPtr(const SharedPtr& sp) : ptr_(sp.ptr_), count_ptr_(sp.count_ptr_), deleter_(sp.deleter_) + SharedPtr(const SharedPtr& sp) : ptr_(sp.ptr_), count_ptr_(sp.count_ptr_), del_(sp.del_) { ++*count_ptr_; } SharedPtr& operator=(SharedPtr sp) { - swap(*this, sp); + swap(sp); return *this; } - SharedPtr(const SharedPtr&& sp) noexcept : SharedPtr() { swap(*this, sp); } + SharedPtr(const SharedPtr&& sp) noexcept : SharedPtr() { swap(sp); } - void reset(T* ptr = nullptr, const std::function& del = DebugDelete()) + void reset(T* ptr = nullptr, DelFuncPtr del = nullptr) { - swap(*this, SharePtr(ptr, del)); + SharedPtr tmp(ptr, del); + swap(tmp); } - void swap(SharedPtr& r) noexcept { swap(*this, r); } + void swap(SharedPtr& r) noexcept + { + using std::swap; + swap(ptr_, r.ptr_); + swap(count_ptr_, r.count_ptr_); + swap(del_, r.del_); + } T* get() const noexcept { return ptr_; } T& operator*() const noexcept { return *get(); } @@ -59,7 +57,7 @@ template class SharedPtr { private: T* ptr_ = nullptr; size_t* count_ptr_ = nullptr; - std::function deleter_; + DelFuncPtr del_ = nullptr; }; #endif // CP5_EX16_28_SHARED_PTR_H_ \ No newline at end of file diff --git a/ch16/ex16_28_test.cpp b/ch16/ex16_28_test.cpp index 10f48766..a2cdb75b 100644 --- a/ch16/ex16_28_test.cpp +++ b/ch16/ex16_28_test.cpp @@ -1,12 +1,27 @@ +#include "ex16_21_debugdelete.h" #include "ex16_28_shared_ptr.h" +#include "ex16_28_unique_ptr.h" +#include #include struct Foo { Foo() { std::cout << "Foo()\n"; } ~Foo() { std::cout << "~Foo()\n"; } + Foo(const Foo&) { std::cout << "Foo copy ctor\n"; } + Foo(Foo&&) { std::cout << "Foo move ctor\n"; } +}; + +struct Fooo { + Fooo(int n = 0) noexcept : bar(n) { std::cout << "Fooo: constructor, bar = " << bar << '\n'; } + ~Fooo() { std::cout << "Fooo: destructor, bar = " << bar << '\n'; } + int GetBar() const noexcept { return bar; } + +private: + int bar; }; struct D { + void bar() { std::cout << "Call deleter D::bar()...\n"; } void operator()(Foo* p) const { std::cout << "Call delete from function object...\n"; @@ -16,25 +31,65 @@ struct D { int main() { + std::cout << "SharedPtr constructor with no managed object\n"; { - std::cout << "constructor with no managed object\n"; SharedPtr sh1; } + std::cout << "SharedPtr constructor with object\n"; { - std::cout << "constructor with object\n"; SharedPtr sh2(new Foo); - SharedPtr sh3(sh2); std::cout << sh2.use_count() << '\n'; + SharedPtr sh3(sh2); std::cout << sh3.use_count() << '\n'; } + std::cout << "SharedPtr constructor with deleter\n"; { - std::cout << "constructor with object and deleter\n"; - SharedPtr sh4(new Foo, D()); SharedPtr sh5(new Foo, [](Foo* p) { std::cout << "Call delete from lambda...\n"; delete p; }); } + + { + SharedPtr sptr(new Fooo(1)); + std::cout << "The first Fooo's bar is " << sptr->GetBar() << "\n"; + sptr.reset(new Fooo); + std::cout << "The second Fooo's bar is " << sptr->GetBar() << "\n"; + } + + { + std::cout << "======================\nUniquePtr constructor:\n"; + UniquePtr up1; + UniquePtr up1b(nullptr); + UniquePtr up2(new Foo); + + DebugDelete d; + UniquePtr up3(new Foo, d); + UniquePtr up3b(new Foo, d); + UniquePtr up4(new Foo, DebugDelete()); + UniquePtr up5b(std::move(up2)); + UniquePtr up6b(std::move(up3)); + + UniquePtr up7 = std::move(up5b); + Foo* fp = up7.release(); + assert(up7.get() == nullptr); + delete fp; + + up6b.reset(new Foo()); + up6b.reset(nullptr); + + UniquePtr up71(new Fooo(1)); + UniquePtr up72(new Fooo(2)); + + up71.swap(up72); + + std::cout << "up71->val:" << up71->GetBar() << std::endl; + std::cout << "up72->val:" << (up72.get())->GetBar() << std::endl; + + UniquePtr up8(new Foo(), D()); + D& del = up8.get_deleter(); + del.bar(); + } } \ No newline at end of file diff --git a/ch16/ex16_28_unique_ptr.h b/ch16/ex16_28_unique_ptr.h index e69de29b..f58efc23 100644 --- a/ch16/ex16_28_unique_ptr.h +++ b/ch16/ex16_28_unique_ptr.h @@ -0,0 +1,72 @@ +#ifndef CP5_EX16_28_UNIQUE_PTR_H_ +#define CP5_EX16_28_UNIQUE_PTR_H_ + +class Delete { +public: + template void operator()(T* ptr) const { delete ptr; } +}; + +template class UniquePtr { +public: + UniquePtr(T* ptr = nullptr, const D& d = D()) noexcept : ptr_(ptr), deleter_(d) {} + ~UniquePtr() { deleter_(ptr_); } + + UniquePtr(const UniquePtr&) = delete; + UniquePtr& operator=(const UniquePtr&) = delete; + + UniquePtr(UniquePtr&& other) noexcept : ptr_(other.ptr_), deleter_(std::move(other.deleter_)) + { + other.ptr_ = nullptr; + } + + UniquePtr& operator=(UniquePtr&& other) noexcept + { + if (this != &other) { + reset(); + ptr_ = other.ptr_; + deleter_ = std::move(other.deleter_); + other.ptr_ = nullptr; + } + return *this; + } + + UniquePtr& operator=(std::nullptr_t) noexcept + { + reset(); + return *this; + } + + T* release() noexcept + { + T* ret = ptr_; + ptr_ = nullptr; + return ret; + } + + void reset(T* q = nullptr) noexcept + { + deleter_(q); + ptr_ = q; + } + + void swap(UniquePtr& other) noexcept + { + using std::swap; + swap(ptr_, other.ptr_); + swap(deleter_, other.deleter_); + } + + T* get() const noexcept { return ptr_; } + D& get_deleter() noexcept { return deleter_; } + const D& get_deleter() const noexcept { return deleter_; } + explicit operator bool() const noexcept { return ptr_ != nullptr; } + T& operator*() const { return *ptr_; } + T* operator->() const noexcept { return ptr_; } + T& operator[](size_t i) const { return ptr_[i]; } + +private: + T* ptr_ = nullptr; + D deleter_; +}; + +#endif // CP5_EX16_28_UNIQUE_PTR_H_ \ No newline at end of file From b71567a95084219fa98328cfa00fd0c3244b8ce0 Mon Sep 17 00:00:00 2001 From: pezy Date: Wed, 18 Apr 2018 00:15:58 +0800 Subject: [PATCH 04/11] Finished 16.1... --- ch16/README.md | 8 +- ch16/ex16.29/Blob.h | 124 ---------- ch16/ex16.29/DebugDelete.h | 31 --- ch16/ex16.29/main.cpp | 33 --- ch16/ex16.29/shared_pointer.h | 237 ------------------ ch16/ex16.29/unique_pointer.h | 117 --------- ch16/ex16_29_blob.h | 446 ++++++++++++++++++++++++++++++++++ ch16/ex16_29_blob_test.cpp | 29 +++ 8 files changed, 482 insertions(+), 543 deletions(-) delete mode 100644 ch16/ex16.29/Blob.h delete mode 100644 ch16/ex16.29/DebugDelete.h delete mode 100644 ch16/ex16.29/main.cpp delete mode 100644 ch16/ex16.29/shared_pointer.h delete mode 100644 ch16/ex16.29/unique_pointer.h create mode 100644 ch16/ex16_29_blob.h create mode 100644 ch16/ex16_29_blob_test.cpp diff --git a/ch16/README.md b/ch16/README.md index 649d894a..b11055d4 100644 --- a/ch16/README.md +++ b/ch16/README.md @@ -243,11 +243,17 @@ Solution from [How is a template instantiated? - Stack Overflow](https://stackov > Revise your `Blob` class to use your version of `shared_ptr` rather than the library version. +[Blob with SharedPtr](ex16_29_blob.h) | [test](ex16_29_blob_test.cpp) + ## Exercise 16.30 Rerun some of your programs to verify your `shared_ptr` and revised `Blob` classes. (Note: Implementing the `weak_ptr` type is beyond the scope of this Primer, so you will not be able to use the `BlobPtr` class with your revised `Blob`.) +check [Exercise 16.28](#exercise-1628) + ## Exercise 16.31 ->Explain how the compiler might inline the call to the deleter if we used `DebugDelete` with `unique_ptr`. \ No newline at end of file +>Explain how the compiler might inline the call to the deleter if we used `DebugDelete` with `unique_ptr`. + +The compiler will set the default deleter type as `DebugDelete`, which will be executed is known at compile time. \ No newline at end of file diff --git a/ch16/ex16.29/Blob.h b/ch16/ex16.29/Blob.h deleted file mode 100644 index 867a16d3..00000000 --- a/ch16/ex16.29/Blob.h +++ /dev/null @@ -1,124 +0,0 @@ -/*************************************************************************** - * @file Blob.h - * @author Alan.W - * @date 02 Feb 2014 - * @remark This code is for the exercises from C++ Primer 5th Edition - * @note 03 Feb 2014 Add a constructor that takes two iterators to Blob . - * 06 Feb 2014 revise to use custome shared_ptr - ***************************************************************************/ - -#ifndef BLOB_H -#define BLOB_H -#include -#include -#include - -/** - * Blob - * manage a vector through a shared_pointer. - */ -template class Blob -{ -public: - typedef T value_type; - typedef typename std::vector::size_type size_type; - - //! constructors - Blob(); - Blob(std::initializer_list il); - - //! constructor taking two iterators - template - Blob(It b, It e); - - //! number of elements in the Blob - size_type size() const { return data->size(); } - bool empty() const{ return data->empty();} - - void push_back(const T& t) { data->push_back(t); } - void push_back(T&& t) { data->push_back(std::move(t));} - void pop_back(); - - //! element access - T& back(); - T& operator[](size_type i); - - const T& back() const; - const T& operator [](size_type i) const; - -private: - /** - * @oldcode updated Feb 06,2014 @Alan - */ - //std::shared_ptr> data; - - shared_pointer> data; - - //! throw msg if data[i] isn't valid - void check(size_type i, const std::string &msg) const; -}; - -//! default constructor -template -Blob::Blob() : data(std::make_shared>()) -{} - -//! constructor taking initializer_list -template -Blob::Blob(std::initializer_list il): - data(std::make_shared>(il)){ } - -//! constructor taking two iterators -template //for class -template //for this member -Blob::Blob(It b, It e) : - data(std::make_shared>(b,e)) -{} - -template -void Blob::check(size_type i, const std::string &msg) const -{ - if(i >= data->size()) - throw std::out_of_range(msg); -} - -template -T& Blob::back() -{ - check(0,"back on empty Blob"); - return data->back(); -} - -template -const T& Blob::back() const -{ - check(0,"back on empty Blob"); - return data->back(); -} - - -template -T& Blob::operator [](size_type i) -{ - //! if i is too big, check function will throw,preventing access to a nonexistent element - check(i,"subscript out of range"); - return (*data)[i]; -} - - -template -const T& Blob::operator [](size_type i) const -{ - //! if i is too big, check function will throw,preventing access to a nonexistent element - check(i,"subscript out of range"); - return (*data)[i]; -} - -template -void Blob::pop_back() -{ - check(0,"pop_back on empty Blob"); - data->pop_back(); -} - -#endif // BLOB_H diff --git a/ch16/ex16.29/DebugDelete.h b/ch16/ex16.29/DebugDelete.h deleted file mode 100644 index 923dccbe..00000000 --- a/ch16/ex16.29/DebugDelete.h +++ /dev/null @@ -1,31 +0,0 @@ -/*************************************************************************** - * @file DebugDelete.h - * @author Alan.W - * @date 04 Feb 2014 - * @remark This code is for the exercises from C++ Primer 5th Edition - * @note - ***************************************************************************/ - -#ifndef DEBUGDELETE_H -#define DEBUGDELETE_H - -#include - -/** - * @brief The DebugDelete class is a deleter functor using delete - */ -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 // DEBUGDELETE_H diff --git a/ch16/ex16.29/main.cpp b/ch16/ex16.29/main.cpp deleted file mode 100644 index 3a3387a1..00000000 --- a/ch16/ex16.29/main.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/*************************************************************************** - * @file main.cpp - * @author Alan.W - * @date 04 Feb 2014 - * @remark This code is for the exercises from C++ Primer 5th Edition - * @note - ***************************************************************************/ -//! -//! Exercise 16.29: -//! Revise your Blob class to use your version of shared_ptr rather than the -//! library version. -//! - - -#include -#include -#include -#include -#include "DebugDelete.h" -#include "shared_pointer.h" -#include "unique_pointer.h" -#include "Blob.h" - -int main() -{ - Blob b; - b.push_back("sss"); - - - b[0] = "zzzz"; - std::cout << b[0] << "\n"; -} - diff --git a/ch16/ex16.29/shared_pointer.h b/ch16/ex16.29/shared_pointer.h deleted file mode 100644 index d694ead4..00000000 --- a/ch16/ex16.29/shared_pointer.h +++ /dev/null @@ -1,237 +0,0 @@ -/*************************************************************************** - * @file shared_pointer.h - * @author Alan.W - * @date 04 Feb 2014 - * @remark This code is for the exercises from C++ Primer 5th Edition - * @note 06 Feb 2014 ctor taking std::shared_ptr&& added - ***************************************************************************/ -#ifndef SHARED_POINTER_H -#define SHARED_POINTER_H - -#include "DebugDelete.h" -#include -#include - -//! forward declarations needed for friendship - -template class shared_pointer; -template void swap(shared_pointer& lhs, shared_pointer& rhs); - - -/** - * @brief shared_ptr like template class - * @note don't mix this one with std::shared_ptr. - * DebugDelete is the default deleter which can be replaced at run time - */ -template -class shared_pointer -{ - friend void ::swap(shared_pointer& lhs, shared_pointer& rhs); - //! ^^^ -- don't forget this. - -public: - - //! default constructor - shared_pointer() = default; - - //! constructor taking raw pointer. - //! set the refCount as 1 - explicit shared_pointer(T* up, std::function d = DebugDelete()) : - ptr(up), refCount(new std::size_t(1)), deleter(d) { } - - //! ctor taking std::shared_ptr&& i.e. rvalue reference - explicit shared_pointer(std::shared_ptr&& sp, - std::function d = DebugDelete()); - - //! copy constructor. - //! increment useCount for each Copy - shared_pointer(const shared_pointer& sp): - ptr(sp.ptr), refCount(sp.refCount), deleter(sp.deleter) - { ++*refCount; } - - //! move constructor - shared_pointer(shared_pointer&& sp) noexcept; - - //! copy assignment - shared_pointer& operator =(const shared_pointer& rhs); - - //! move assignment - shared_pointer& operator =(shared_pointer&& rhs) noexcept; - - - //! conversion operator - operator bool() const { return ptr ? true : false;} - - //! dereference * arrow -> - T& operator* () const { return *ptr; } - T* operator->() const { return & this->operator *(); } - - //! return useCount - std::size_t use_count() const { return *refCount; } - - //! get the underlying pointer - T* get() const noexcept { return ptr; } - - //! check if the unique user - bool unique() const noexcept { return *refCount == 1;} - - //! swap member - void swap( shared_pointer& rhs) { ::swap(*this, rhs); } - - //! if unique user, free the object pointed to - void reset() noexcept { decrement_n_destroy(); } - - //! make prt point where p pointing and create a new coount for it - void reset(T* p); - - //! reset to point where p is pointing and change deleter to d. - void reset(T *p, const std::function& d) - { reset(p); deleter = d; } - - - ~shared_pointer() - { - decrement_n_destroy(); - } -private: - - T* ptr = nullptr; - std::size_t* refCount = new std::size_t(0); - - //! any functor lambda or function pointer that matched this - //! signature can replace the default one at run time. - std::function deleter{DebugDelete()}; - //! ^~~~~~~~~~~~~~^ - //! here: = doesn't work, another way is initializing it in constructor. - - //! utilities - void decrement_n_destroy(); -}; - - - -/** - * @brief swap and big 5 - */ -template -inline void -swap(shared_pointer& lhs, shared_pointer& rhs) -{ - using std::swap; - swap(lhs.ptr, rhs.ptr); - swap(lhs.refCount, rhs.refCount); - swap(lhs.deleter, rhs.deleter); -} - - -/** - * @brief ctor taking std::shared_ptr&& i.e. rvalue reference - * an interface between shared_pointer and std::shared_ptr. - * only rvalue AND unique ownership can use this ctor. - */ -template -inline -shared_pointer::shared_pointer(std::shared_ptr&& sp, - std::function d) -{ - if(sp.unique()) - *this = shared_pointer(new T(*sp), d); - else - throw std::runtime_error - ("only unique and rvalue reference can transfer ownership--@Alan\n"); -} - - -//! move constructor -template -inline -shared_pointer::shared_pointer(shared_pointer&& sp) noexcept: - ptr(sp.ptr), refCount(sp.refCount), deleter(std::move(sp.deleter)) -{ - sp.ptr = nullptr; - sp.refCount = nullptr; -} - - -//! copy assignment -template -inline shared_pointer& -shared_pointer::operator =(const shared_pointer& rhs) -{ - //! increment rhs.refCount first to ensure safty when self-assignment - ++*rhs.refCount; - - //! for lhs: - decrement_n_destroy(); - - //! copy datastructure from rhs to this. - ptr = rhs.ptr; - refCount = rhs.refCount; - deleter = rhs.deleter; - - return *this; -} - - -//! move assignment -template -inline shared_pointer& -shared_pointer::operator =(shared_pointer&& rhs) noexcept -{ - //! for lhs - decrement_n_destroy(); - - //! swap two sides - ::swap(*this, rhs); - - std::cout << "shared_pointer::move=\n"; - - return *this; -} - - -//! make prt point where p pointing and create a new coount for it -template -inline void -shared_pointer::reset(T* p) -{ - if(ptr != p) - { - decrement_n_destroy(); - ptr = p; - refCount = new std::size_t(1); - } -} - - -/** - *@brief operators: << - **/ - -template -inline std::ostream& -operator <<(std::ostream& os, shared_pointer p) -{ - os << p.get(); - return os; -} - - -//! utilities for decrement and delete using deleter. -template -inline void -shared_pointer::decrement_n_destroy() -{ - if(ptr) - { - if (--*refCount == 0) - { - delete refCount; - deleter(ptr); - } - refCount = nullptr; - ptr = nullptr; - } -} - -#endif // SHARED_POINTER_H diff --git a/ch16/ex16.29/unique_pointer.h b/ch16/ex16.29/unique_pointer.h deleted file mode 100644 index 8a49e2c7..00000000 --- a/ch16/ex16.29/unique_pointer.h +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef UNIQUE_POINTER_H -#define UNIQUE_POINTER_H - -#include - -//! forward declarations for friendship - -template class unique_pointer; -template void - swap(unique_pointer& lhs, unique_pointer& rhs); - -/** - * @brief std::unique_ptr like class template. - */ -template -class unique_pointer -{ - friend void swap(unique_pointer& lhs, unique_pointer& rhs); - -public: - //! preventing copy and assignment - unique_pointer(const unique_pointer&) = delete; - unique_pointer& operator = (const unique_pointer&) = delete; - - //! default constructor and one taking T* - unique_pointer() = default; - explicit unique_pointer(T* up): ptr(up) { } - - //! move constructor - unique_pointer(unique_pointer&& up) noexcept - : ptr(up.ptr) { up.ptr = nullptr; } - - //! move assignment - unique_pointer& operator =(unique_pointer&& rhs) noexcept; - - //! std::nullptr_t assignment - unique_pointer& operator =(std::nullptr_t n) noexcept; - - - - //! operator overloaded : * -> bool - T& operator *() const { return *ptr; } - T* operator ->() const { return & this->operator *(); } - operator bool() const { return ptr ? true : false; } - - //! return the underlying pointer - T* get() const noexcept { return ptr;} - - //! swap member using swap friend - void swap(unique_pointer &rhs) {::swap(*this, rhs);} - - //! free and make it point to nullptr or to p's pointee. - void reset() noexcept { deleter(ptr); ptr = nullptr; } - void reset(T* p) noexcept { deleter(ptr); ptr = p; } - - //! return ptr and make ptr point to nullptr. - T* release(); - - - ~unique_pointer() - { - deleter(ptr); - } -private: - T* ptr = nullptr; - D deleter = D(); -}; - - -//! swap -template -inline void -swap(unique_pointer& lhs, unique_pointer& rhs) -{ - using std::swap; - swap(lhs.ptr, rhs.ptr); - swap(lhs.deleter, rhs.deleter); -} - -//! move assignment -template -inline unique_pointer& -unique_pointer::operator =(unique_pointer&& rhs) noexcept -{ - //! prevent self-assignment - if(this->ptr != rhs.ptr) - { - deleter(ptr); - ptr = nullptr; - ::swap(*this, rhs); - } - return *this; -} - - -//! std::nullptr_t assignment -template -inline unique_pointer& -unique_pointer::operator =(std::nullptr_t n) noexcept -{ - if(n == nullptr) - { - deleter(ptr); ptr = nullptr; - } - return *this; -} - - //! relinquish contrul by returnning ptr and making ptr point to nullptr. -template -inline T* -unique_pointer::release() -{ - T* ret = ptr; - ptr = nullptr; - return ret; -} -#endif // UNIQUE_POINTER_H diff --git a/ch16/ex16_29_blob.h b/ch16/ex16_29_blob.h new file mode 100644 index 00000000..024332ee --- /dev/null +++ b/ch16/ex16_29_blob.h @@ -0,0 +1,446 @@ +#ifndef CP5_EX16_24_BLOB_H_ +#define CP5_EX16_24_BLOB_H_ + +#include +using std::vector; + +#include +using std::initializer_list; + +#include "ex16_28_shared_ptr.h" +#include +#include + +template class BlobPtr; +template class ConstBlobPtr; +template class Blob; + +//============================================================================== +// Blob - custom vector. +//============================================================================== + +template class Blob { + friend class ConstBlobPtr; + friend class BlobPtr; + friend bool operator==(const Blob& lhs, const Blob& rhs) { return *lhs.data == *rhs.data; } + friend bool operator!=(const Blob& lhs, const Blob& rhs) { return !(lhs == rhs); } + friend bool operator<(const Blob& lhs, const Blob& rhs) + { + return std::lexicographical_compare(lhs.data->begin(), lhs.data->end(), rhs.data->begin(), + rhs.data->end()); + } + friend bool operator>(const Blob& lhs, const Blob& rhs) { return rhs < lhs; } + friend bool operator<=(const Blob& lhs, const Blob& rhs) { return !(rhs < lhs); } + friend bool operator>=(const Blob& lhs, const Blob& rhs) { return !(lhs < rhs); } + +public: + using size_type = typename vector::size_type; + + Blob() : data(new vector()) {} + Blob(initializer_list il) : data(new vector(il)) {} + template Blob(It b, It e) : data(new vector(b, e)) {} + + Blob(const Blob& b) : data(new vector(*b.data)) {} + Blob& operator=(const Blob& b); + + Blob(Blob&& b) NOEXCEPT : data(std::move(b.data)) {} + Blob& operator=(Blob&& b) NOEXCEPT; + + BlobPtr begin(); + BlobPtr end(); + + ConstBlobPtr cbegin() const; + ConstBlobPtr cend() const; + + T& operator[](size_t n); + const T& operator[](size_t n) const; + + size_type size() const { return data->size(); } + bool empty() const { return data->empty(); } + + void push_back(const T& t) { data->push_back(t); } + void push_back(T&& s) { data->push_back(std::move(s)); } + + void pop_back(); + T& front(); + T& back(); + const T& front() const; + const T& back() const; + +private: + void check(size_type, const T&) const; + + SharedPtr> data; +}; + +//------------------------------------------------------------------------------ +// member function. +//------------------------------------------------------------------------------ + +template Blob& Blob::operator=(const Blob& b) +{ + data = new vector(*b.data); + return *this; +} + +template Blob& Blob::operator=(Blob&& b) NOEXCEPT +{ + if (this != &b) { + data = std::move(b.data); + b.data = nullptr; + } + + return *this; +} + +template BlobPtr Blob::begin() +{ + return BlobPtr(*this); +} + +template BlobPtr Blob::end() +{ + return BlobPtr(*this, data->size()); +} + +template ConstBlobPtr Blob::cbegin() const +{ + return ConstBlobPtr(*this); +} + +template ConstBlobPtr Blob::cend() const +{ + return ConstBlobPtr(*this, data->size()); +} + +template inline void Blob::pop_back() +{ + check(0, "pop_back on empty Blob"); + data->pop_back(); +} + +template inline T& Blob::front() +{ + check(0, "front on empty Blob"); + return data->front(); +} + +template inline T& Blob::back() +{ + check(0, "back on empty Blob"); + return data->back(); +} + +template inline const T& Blob::front() const +{ + check(0, "front on empty Blob"); + return data->front(); +} + +template inline const T& Blob::back() const +{ + check(0, "back on empty Blob"); + return data->back(); +} + +template inline void Blob::check(size_type i, const T& msg) const +{ + if (i >= data->size()) throw std::out_of_range(msg); +} + +template inline T& Blob::operator[](size_t n) +{ + check(n, "out of range"); + return data->at(n); +} + +template inline const T& Blob::operator[](size_t n) const +{ + check(n, "out of range"); + return data->at(n); +} + +//================================================================================= +// BlobPtr - custom iterator of Blob +//================================================================================= + +template class BlobPtr { + friend bool operator==(const BlobPtr& lhs, const BlobPtr& rhs) + { + return lhs.curr == rhs.curr; + } + friend bool operator!=(const BlobPtr& lhs, const BlobPtr& rhs) { return !(lhs == rhs); } + friend bool operator<(const BlobPtr& lhs, const BlobPtr& rhs) + { + return lhs.curr < rhs.curr; + } + friend bool operator>(const BlobPtr& lhs, const BlobPtr& rhs) + { + return lhs.curr > rhs.curr; + } + friend bool operator<=(const BlobPtr& lhs, const BlobPtr& rhs) + { + return lhs.curr <= rhs.curr; + } + friend bool operator>=(const BlobPtr& lhs, const BlobPtr& rhs) + { + return lhs.curr >= rhs.curr; + } + +public: + BlobPtr() : curr(0) {} + BlobPtr(Blob& s, size_t sz = 0) : wptr(s.data), curr(sz) {} + + T& operator*() const; + T* operator->() const; + BlobPtr& operator++(); + BlobPtr& operator--(); + BlobPtr operator++(int); + BlobPtr operator--(int); + BlobPtr& operator+=(size_t); + BlobPtr& operator-=(size_t); + BlobPtr operator+(size_t) const; + BlobPtr operator-(size_t) const; + + T& operator[](size_t n); + const T& operator[](size_t n) const; + +private: + SharedPtr> check(size_t, const T&) const; + + std::weak_ptr> wptr; + size_t curr; +}; + +//------------------------------------------------------------------------------ +// member function. +//------------------------------------------------------------------------------ + +template T& BlobPtr::operator*() const +{ + auto p = check(curr, "dereference past end"); + return (*p)[curr]; +} + +template T* BlobPtr::operator->() const +{ + return &this->operator*(); +} + +template inline BlobPtr& BlobPtr::operator++() +{ + check(curr, "increment past end of BlobPtr"); + ++curr; + return *this; +} + +template inline BlobPtr& BlobPtr::operator--() +{ + --curr; + check(-1, "decrement past begin of BlobPtr"); + return *this; +} + +template inline BlobPtr BlobPtr::operator++(int) +{ + BlobPtr ret = *this; + ++*this; + return ret; +} + +template inline BlobPtr BlobPtr::operator--(int) +{ + BlobPtr ret = *this; + --*this; + return ret; +} + +template inline BlobPtr& BlobPtr::operator+=(size_t n) +{ + curr += n; + check(curr, "increment past end of BlobPtr"); + return *this; +} + +template inline BlobPtr& BlobPtr::operator-=(size_t n) +{ + curr -= n; + check(curr, "increment past end of BlobPtr"); + return *this; +} + +template inline BlobPtr BlobPtr::operator+(size_t n) const +{ + BlobPtr ret = *this; + ret += n; + return ret; +} + +template inline BlobPtr BlobPtr::operator-(size_t n) const +{ + BlobPtr ret = *this; + ret -= n; + return ret; +} + +template inline SharedPtr> BlobPtr::check(size_t i, const T& msg) const +{ + auto ret = wptr.lock(); + if (!ret) throw std::runtime_error("unbound BlobPtr"); + if (i >= ret->size()) throw std::out_of_range(msg); + return ret; +} + +template inline T& BlobPtr::operator[](size_t n) +{ + auto p = check(n, "dereference out of range."); + return (*p)[n]; +} + +template inline const T& BlobPtr::operator[](size_t n) const +{ + auto p = check(n, "dereference out of range."); + return (*p)[n]; +} + +//================================================================================= +// ConstBlobPtr - custom const_iterator of Blob +//================================================================================= + +template class ConstBlobPtr { + friend bool operator==(const ConstBlobPtr& lhs, const ConstBlobPtr& rhs) + { + return lhs.curr == rhs.curr; + } + friend bool operator!=(const ConstBlobPtr& lhs, const ConstBlobPtr& rhs) + { + return !(lhs == rhs); + } + friend bool operator<(const ConstBlobPtr& lhs, const ConstBlobPtr& rhs) + { + return lhs.curr < rhs.curr; + } + friend bool operator>(const ConstBlobPtr& lhs, const ConstBlobPtr& rhs) + { + return lhs.curr > rhs.curr; + } + friend bool operator<=(const ConstBlobPtr& lhs, const ConstBlobPtr& rhs) + { + return lhs.curr <= rhs.curr; + } + friend bool operator>=(const ConstBlobPtr& lhs, const ConstBlobPtr& rhs) + { + return lhs.curr >= rhs.curr; + } + +public: + ConstBlobPtr() : curr(0) {} + ConstBlobPtr(const Blob& s, size_t sz = 0) : wptr(s.data), curr(sz) {} + + const T& operator*() const; + const T* operator->() const; + ConstBlobPtr& operator++(); + ConstBlobPtr& operator--(); + ConstBlobPtr operator++(int); + ConstBlobPtr operator--(int); + ConstBlobPtr& operator+=(size_t); + ConstBlobPtr& operator-=(size_t); + ConstBlobPtr operator+(size_t) const; + ConstBlobPtr operator-(size_t) const; + + const T& operator[](size_t n) const; + +private: + std::SharedPtr> check(size_t, const T&) const; + + std::weak_ptr> wptr; + size_t curr; +}; + +//------------------------------------------------------------------------------ +// member function. +//------------------------------------------------------------------------------ + +template inline const T& ConstBlobPtr::operator*() const +{ + auto p = check(curr, "dereference past end"); + return (*p)[curr]; +} + +template inline const T* ConstBlobPtr::operator->() const +{ + return &this->operator*(); +} + +template inline ConstBlobPtr& ConstBlobPtr::operator++() +{ + check(curr, "increment past end of ConstBlobPtr"); + ++curr; + return *this; +} + +template inline ConstBlobPtr& ConstBlobPtr::operator--() +{ + --curr; + check(-1, "decrement past begin of ConstBlobPtr"); + return *this; +} + +template inline ConstBlobPtr ConstBlobPtr::operator++(int) +{ + ConstBlobPtr ret = *this; + ++*this; + return ret; +} + +template inline ConstBlobPtr ConstBlobPtr::operator--(int) +{ + ConstBlobPtr ret = *this; + --*this; + return ret; +} + +template inline ConstBlobPtr& ConstBlobPtr::operator+=(size_t n) +{ + curr += n; + check(curr, "increment past end of ConstBlobPtr"); + return *this; +} + +template inline ConstBlobPtr& ConstBlobPtr::operator-=(size_t n) +{ + curr -= n; + check(curr, "increment past end of ConstBlobPtr"); + return *this; +} + +template inline ConstBlobPtr ConstBlobPtr::operator+(size_t n) const +{ + ConstBlobPtr ret = *this; + ret += n; + return ret; +} + +template inline ConstBlobPtr ConstBlobPtr::operator-(size_t n) const +{ + ConstBlobPtr ret = *this; + ret -= n; + return ret; +} + +template +inline std::SharedPtr> ConstBlobPtr::check(size_t i, const T& msg) const +{ + auto ret = wptr.lock(); + if (!ret) throw std::runtime_error("unbound BlobPtr"); + if (i >= ret->size()) throw std::out_of_range(msg); + return ret; +} + +template inline const T& ConstBlobPtr::operator[](size_t n) const +{ + auto p = check(n, "dereference out of range."); + return (*p)[n]; +} + +#endif // CP5_EX16_24_BLOB_H_ diff --git a/ch16/ex16_29_blob_test.cpp b/ch16/ex16_29_blob_test.cpp new file mode 100644 index 00000000..737ab482 --- /dev/null +++ b/ch16/ex16_29_blob_test.cpp @@ -0,0 +1,29 @@ +#include "ex16_24_blob.h" +#include +#include + +int main() +{ + Blob sb1{"a", "b", "c"}; + Blob sb2 = sb1; + + sb2[2] = "b"; + + if (sb1 > sb2) { + for (auto iter = sb2.cbegin(); iter != sb2.cend(); ++iter) { + std::cout << *iter << " "; + } + std::cout << std::endl; + } + + ConstBlobPtr iter(sb2); + std::cout << iter->size() << std::endl; + + std::vector vec{"good", "for", "you"}; + Blob sb3(vec.begin(), vec.end()); + + for (auto&& s : sb3) { + std::cout << s << " "; + } + std::cout << "\n"; +} From 8a3db4318e78b284dd5fec8bb30ad63bad58030d Mon Sep 17 00:00:00 2001 From: pezy Date: Thu, 19 Apr 2018 23:21:14 +0800 Subject: [PATCH 05/11] fixed #109 --- ch16/README.md | 75 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/ch16/README.md b/ch16/README.md index b11055d4..b292391c 100644 --- a/ch16/README.md +++ b/ch16/README.md @@ -256,4 +256,77 @@ check [Exercise 16.28](#exercise-1628) >Explain how the compiler might inline the call to the deleter if we used `DebugDelete` with `unique_ptr`. -The compiler will set the default deleter type as `DebugDelete`, which will be executed is known at compile time. \ No newline at end of file +The compiler will set the default deleter type as `DebugDelete`, which will be executed is known at compile time. + +## Exercise 16.32 + +> What happens during template argument deduction? + +During template argument deduction, the compiler uses types of the arguments in the call to find the template arguments that generate a version of the function that best matches the given call. + +## Exercise 16.33 + +> Name two type conversions allowed on function arguments involved in template argument deduction. + +1. `const` conversions +2. Array- or function-to-pointer conversions + +## Exercise 16.34 + +> Given only the following code, explain whether each of these calls is legal. If so, what is the type of `T`? If not, why not? +> ```cpp +> template int compare(const T&, const T&); +> (a) compare("hi", "world"); +> (b) compare("bye", "dad"); +> ``` + +- (a): illegal, as two types are different, the first type being `const char[3]` ,second `const char[6]` +- (b): legal, the type is `const char(&)[4]`. + +## Exercise 16.35 + +>Which, if any, of the following calls are errors? If the call is legal, what is the type of T? If the call is not legal, what is the problem? +> ```cpp +> template T calc(T, int); +> template T fcn(T, T); +> double d; float f; char c; +> (a) calc(c, 'c'); +> (b) calc(d, f); +> (c) fcn(c, 'c'); +> (d) fcn(d, f); +> ``` + +- (a) legal, type is `char`. +- (b) legal, type is `double`. +- (c) legal, type is `char`. +- (d) illegal, `d` is `double`, but `f` is `float`, they are totally different type. + +## Exercise 16.36 + +> What happens in the following calls: +> ```cpp +> template f1(T, T); +> template int i = 0, j = 42, *p1 = &i, *p2 = &j; +> const int *cp1 = &i, *cp2 = &j; +> (a) f1(p1, p2); +> (b) f2(p1, p2); +> (c) f1(cp1, cp2); +> (d) f2(cp1, cp2); +> (e) f1(p1, cp1); +> (f) f2(p1, cp1); +> ``` + +At first, there are some error in function declarations. + +- `f1`, `f2` should have return type, maybe `void`? +- In `f2`, `typename T2)` should be `typename T2>`. + +Then, the answers: + +- (a) `T` is `int*` +- (b) `T1` and `T2` are both `int*` +- (c) `T` is `const int*` +- (d) `T1` and `T2` are both `const int*` +- (e) **error**, `p1` is `int*`, `cp1` is `const int*`, they are different type +- (f) `T1` is `int*`, `T2` is `const int*` \ No newline at end of file From 134ceb91874fd52337a2f030aa296e756c6a3d98 Mon Sep 17 00:00:00 2001 From: pezy Date: Thu, 19 Apr 2018 23:21:42 +0800 Subject: [PATCH 06/11] remove the old answer. --- ch16/ex16.32.33.34.35.36/main.cpp | 85 ------------------------------- 1 file changed, 85 deletions(-) delete mode 100644 ch16/ex16.32.33.34.35.36/main.cpp diff --git a/ch16/ex16.32.33.34.35.36/main.cpp b/ch16/ex16.32.33.34.35.36/main.cpp deleted file mode 100644 index 95b77083..00000000 --- a/ch16/ex16.32.33.34.35.36/main.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/*************************************************************************** - * @file main.cpp - * @author Alan.W - * @date 04 Feb 2014 - * @remark This code is for the exercises from C++ Primer 5th Edition - * @note - ***************************************************************************/ -//! -//! Exercise 16.32: -//! What happens during template argument deduction? -// The process of determining the template arguments from the function arguments -// is known as template argument deduction. During template argument deduction, -// the compiler uses types of the arguments in the call to find the template -// arguments that generate a version of the function that best matches the given -// call. -//! -//! Exercise 16.33: -//! Name two type conversions allowed on function arguments involved in template -//! argument deduction. -// • const conversions: A function parameter that is a reference (or pointer) -// to a const can be passed a reference (or pointer) to a nonconst object -// (§ 4.11.2, p. 162). -// -// • Array- or function-to-pointer conversions: If the function parameter is -// not a reference type, then the normal pointer conversion will be applied -// to arguments of array or function type. An array argument will be converted -// to a pointer to its first element. Similarly, a function argument will be -// converted to a pointer to the function’s type (§ 4.11.2, p. 161). -//! -//! Exercise 16.34: -//! Given only the following code, explain whether each of these calls is legal. -//! If so, what is the type of T? If not, why not? -//! template int compare(const T&, const T&); -//! compare("hi", "world"); -// It didn't complie, as two types are different, the first type being char[3] ,second char[6] -//! compare("bye", "dad"); -// the type should be pointer to char i.e. char* -//! -//! Exercise 16.35: -//! Which, if any, of the following calls are errors? If the call is legal, what -//! is the type of T? If the call is not legal, what is the problem? -//! template T calc(T, int); -//! template T fcn(T, T); -//! double d; float f; char c; -//! (a) calc(c, 'c'); -- legal,T is a char -//! (b) calc(d, f); -- legal,T is a double -//! (c) fcn(c, 'c'); -- legal,T is a char -//! (d) fcn(d, f); -- illegal, arguments d and f are double and float repectively -//! -//! Exercise 16.36: -//! What happens in the following calls: -//! template f1(T, T); -//! template -template -void f1(T lhs, T rhs) { } - -template -void f2(T1 t1, T2 t2) -{ - ; -} - - - - -int main() -{ - int i = 0, j = 42, *p1 = &i, *p2 = &j; - const int *cp1 = &i, *cp2 = &j; - - f2(p1, cp1); - - -} From 4cd02dd6bafffbcde6f6df0a14d2c36375f12882 Mon Sep 17 00:00:00 2001 From: pezy Date: Thu, 19 Apr 2018 23:27:54 +0800 Subject: [PATCH 07/11] fixed #126 --- ch04/README.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ch04/README.md b/ch04/README.md index 3e01eb84..6e764a9c 100644 --- a/ch04/README.md +++ b/ch04/README.md @@ -256,13 +256,11 @@ if `grade > 90`, first conditional operator's result is `high pass`. so the fina ## Exercise 4.25 -> What is the value of ~'q' \<< 6 on a machine with 32-bit ints and 8 bit chars, that uses Latin-1 character set in which 'q' has the bit pattern 01110001? +> What is the value of `~'q' << 6` on a machine with 32-bit `int`s and 8 bit `char`s, that uses Latin-1 character set in which '`q`' has the bit pattern `01110001`? -The final value in decimal representation is `-7296`. +We see the value of `~ 'q'` is negative. Left-shifting a negative value has **undefined behaviour**. -The bitwise NOT operator (`~`) yields us the Ones' Complement of `0000 0000 0000 0000 0000 0000 0111 0001`, which is `1111 1111 1111 1111 1111 1111 1000 1110`. The value of `1111 1111 1111 1111 1111 1111 1000 1110` in decimal form is `-114`. This may come as a surprise to some as the unsigned value of said binary sequence is `4294967182`. The most significant bit (the left-most bit, commonly referred to as the sign bit) is however "turned on", or `1`, which signifies a negation operation on that particular bit. The value of that particular bit is then `-2147483648`. - -We then shift the bits `6` digits to the left, which yields us `1111 1111 1111 1111 1110 0011 1000 0000`. Overflowing bits were discarded. The decimal representation of the binary sequence is `-7296`. +check ## Exercise 4.26 From 062d4c54545280b5313ec8f83d3ed9bec7c4502b Mon Sep 17 00:00:00 2001 From: pezy chen Date: Fri, 11 May 2018 00:42:51 +0800 Subject: [PATCH 08/11] Added 16.37 ~ 41 --- ch16/README.md | 48 ++++++++++++++++++++++++++++++++- ch16/ex16.37.38.39/main.cpp | 53 ------------------------------------- ch16/ex16.40/main.cpp | 48 --------------------------------- 3 files changed, 47 insertions(+), 102 deletions(-) delete mode 100644 ch16/ex16.37.38.39/main.cpp delete mode 100644 ch16/ex16.40/main.cpp diff --git a/ch16/README.md b/ch16/README.md index b292391c..557095f2 100644 --- a/ch16/README.md +++ b/ch16/README.md @@ -329,4 +329,50 @@ Then, the answers: - (c) `T` is `const int*` - (d) `T1` and `T2` are both `const int*` - (e) **error**, `p1` is `int*`, `cp1` is `const int*`, they are different type -- (f) `T1` is `int*`, `T2` is `const int*` \ No newline at end of file +- (f) `T1` is `int*`, `T2` is `const int*` + +## Exercise 16.37 + +> The library `max` function has two function parameters and returns the larger of its arguments. This function has one template type parameter. Could you call `max` passing it an int and a double? If so, how? If not, why not? + +No, I could not. Because the arguments to `max` must have the same type. + +## Exercise 16.38 + +> When we call `make_shared` (12.1.1, p. 451), we have to provide an explicit template argument. Explain why that argument is needed and how it is used. + +Because when we call `make_shared`, it is allowed for no argument. Then, we have nothing to deduce the type of the return type. + +## Exercise 16.39 + +> Use an explicit template argument to make it sensible to pass two string literals to the original version of compare from 16.1.1 (p.652). + +```cpp +std::cout << compare("czwp", "czyz") << std::endl; + ^^^^^^^^^^^^^ +``` + +## Exercise 16.40 + +> Is the following function legal? If not, why not? If it is legal, what, if any, are the restrictions on the argument type(s) that can be passed, and what is the return type? + +```cpp +template +auto fcn3(It beg, It end) -> decltype(*beg + 0) { + // process the range + return *beg; // return a copy of an element from the range +} +``` + +legal. But only type that support this + 0 operation can be passed, and the return type depends on the what type the operator `+` return. + +## Exercise 16.41 + +>Write a version of `sum` with a return type that is guaranteed to be large enough to hold the result of the addition. + +```cpp +template +auto sum(T1 a, T2 b) -> decltype(a + b) { + return a + b; +} +``` \ No newline at end of file diff --git a/ch16/ex16.37.38.39/main.cpp b/ch16/ex16.37.38.39/main.cpp deleted file mode 100644 index 08b83c3b..00000000 --- a/ch16/ex16.37.38.39/main.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/*************************************************************************** - * @file main.cpp - * @author Alan.W - * @date 07 Feb 2014 - * @remark This code is for the exercises from C++ Primer 5th Edition - * @note - ***************************************************************************/ -//! -//! Exercise 16.37: -//! The library max function has two function parameters and returns the -//! larger of its arguments. This function has one template type parameter. -//! Could you call max passing it an int and a double? If so, how? If not, -//! why not? -// If so, it doesn't compile, because the two argument must be the same type or -// convertible. -// -//! Exercise 16.38: -//! When we call make_shared (§ 12.1.1, p. 451), we have to provide an -//! explicit template argument. Explain why that argument is needed and -//! how it is used. -//! -// without specified type given, make_shared has no possibility to -// to determine how big the size it should allocate, which is the reason. -// -// Depending on the type specified, make_shared allocates proper size of memory -// space and returns a proper type of shared_ptr pointing to it. -//! -//! Exercise 16.39: -//! Use an explicit template argument to make it sensible to pass two string -//! literals to the original version of compare from § 16.1.1 (p. 652). -//! - - -#include - - -template -int compare(const T &v1, const T &v2) -{ - if (v1 < v2) return -1; - if (v2 < v1) return 1; - return 0; -} - -int main() -{ - std::cout << compare("sss","aaa") << "\n"; - //! ^^^^^^^^^^^^^ - //! There is a normal conversion here, since it's an explicit argument. - - - -} diff --git a/ch16/ex16.40/main.cpp b/ch16/ex16.40/main.cpp deleted file mode 100644 index 5ac595c4..00000000 --- a/ch16/ex16.40/main.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/*************************************************************************** - * @file main.cpp - * @author Alan.W - * @date 07 Feb 2014 - * @remark This code is for the exercises from C++ Primer 5th Edition - * @note - ***************************************************************************/ -//! -//! Exercise 16.40: -//! Is the following function legal? If not, why not? If it is legal, what, -//! if any, are the restrictions on the argument type(s) that can be passed, -//! and what is the return type? -//! legal. -//! As shown below, only type that support this + 0 operation can be passed. -//! the return type depends on the what type the operator + returns. In the case -//! below, the return type is Bar. -//! - - -#include -#include -#include - -class Bar{}; - -Bar operator +(Bar lhs, int) -{ - return lhs; -} - -template -auto fcn3(It beg, It end) -> decltype(*beg + 0) -{ - return *beg; // return a copy of an element from the range -} - -int main() -{ - - std::vector v; - v.push_back(Bar()); - - Bar b = fcn3(v.begin(), v.end()); - ; - ; - - -} From db498da9cd7b7afee91e02648295e554cbc461b3 Mon Sep 17 00:00:00 2001 From: pezy chen Date: Fri, 11 May 2018 00:56:14 +0800 Subject: [PATCH 09/11] Fixed #135 --- ch16/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ch16/README.md b/ch16/README.md index 557095f2..b6d49820 100644 --- a/ch16/README.md +++ b/ch16/README.md @@ -375,4 +375,6 @@ template auto sum(T1 a, T2 b) -> decltype(a + b) { return a + b; } -``` \ No newline at end of file +``` + +More safer solution: <[Better `sum`](ex16_41_sum.cpp)> \ No newline at end of file From 9cee9eb221d0de684c8fd09ffc3dd6b7526db7b3 Mon Sep 17 00:00:00 2001 From: pezy chen Date: Mon, 14 May 2018 00:31:55 +0800 Subject: [PATCH 10/11] Finished 16.2 --- ch16/README.md | 54 +++++++++++++++++- ch16/ex16.42.43.44.45.46/main.cpp | 91 ------------------------------- ch16/ex16.47/main.cpp | 63 --------------------- ch16/ex16_47_flip.cpp | 24 ++++++++ 4 files changed, 77 insertions(+), 155 deletions(-) delete mode 100644 ch16/ex16.42.43.44.45.46/main.cpp delete mode 100644 ch16/ex16.47/main.cpp create mode 100644 ch16/ex16_47_flip.cpp diff --git a/ch16/README.md b/ch16/README.md index b6d49820..789de7ba 100644 --- a/ch16/README.md +++ b/ch16/README.md @@ -377,4 +377,56 @@ auto sum(T1 a, T2 b) -> decltype(a + b) { } ``` -More safer solution: <[Better `sum`](ex16_41_sum.cpp)> \ No newline at end of file +More safer solution: <[Better `sum`](ex16_41_sum.cpp)> + +## Exercise 16.42 + +> Determine the type of T and of val in each of the following calls: +> ```cpp +> template void g(T&& val); +> int i = 0; const int ci = i; +> (a) g(i); +> (b) g(ci); +> (c) g(i * ci); +> ``` + +- (a) `int&` +- (b) `const int&` +- (c) `int` + +## Exercise 16.43 + +> Using the function defined in the previous exercise, what would the template parameter of `g` be if we called `g(i = ci)`? + +`int&` + +## Exercise 16.44 + +> Using the same three calls as in the first exercise, determine the types for `T` if `g`’s function parameter is declared as `T` (not `T&&`). What if `g`’s function parameter is `const T&`? + +Whatever `g`'s function parameter is declared as `T` or `const T&`, the `T`'s type in this three case would always `int`. + +## Exercise 16.45 + +> Given the following template, explain what happens if we call `g` on a literal value such as 42. What if we call `g` on a variable of type `int`? +> ```cpp +> template void g(T&& val) { vector v; } +> ``` + +If we call `g` on a literal value such as 42, `T` should be `int`, and we get a tempoary variable `v`, which type is `vector`. If we call `g` on a variable of type `int`, then `val` should be a lvalue, `T` should be `int&`(because `int& &&` ==> `int&`), then we would declared a `v` as `vector`. But the component type of `vector` must be [assignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable), the references are not assignable, thus, `vector` is not allowed, the compiler would complain about it. + +## Exercise 16.46 + +> Explain this loop from `StrVec::reallocate` in 13.5 (p.530): +> ```cpp +> for (size_t i = 0; i != size(); ++i) +> alloc.construct(dest++, std::move(*elem++)); +> ``` + +Since C++11, [`std::allocator::construct`](http://en.cppreference.com/w/cpp/memory/allocator/construct)'s second parameter is `Args&&... args`. `*elem++` is a certain lvalue, and would be casted to a rvalue reference by `std::move`, then the `construct` would call the move constructor of `std::string` rather than copy constructor. + +## Exercise 16.47 + +> Write your own version of the flip function and test it by calling functions that have lvalue and rvalue reference parameters. + +[flip and test](ex16_47_flip.cpp) \ No newline at end of file diff --git a/ch16/ex16.42.43.44.45.46/main.cpp b/ch16/ex16.42.43.44.45.46/main.cpp deleted file mode 100644 index fd6e07be..00000000 --- a/ch16/ex16.42.43.44.45.46/main.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/*************************************************************************** - * @file main.cpp - * @author Alan.W - * @date 07 Feb 2014 - * @remark This code is for the exercises from C++ Primer 5th Edition - * @note - ***************************************************************************/ -//! -//! Exercise 16.42: -//! Determine the type of T and of val in each of the following calls: -//! template void g(T&& val); -//! int i = 0; const int ci = i; -//! (a) g(i); -// since i is lvalue, T is deduced as int&, val is int& && collapsing to int& -//! (b) g(ci); -// since ci is lvaue, T is deduced as const int&, val is const int& && collapsing to const int& -//! (c) g(i * ci); -// since i * ci is rvalue, T is deduced as int&&, val is int&& && colapsing to int&& -//! -//! Exercise 16.43: -//! Using the function defined in the previous exercise, what would the template -//! parameter of g be if we called g(i = ci)? -// (i = ci) returns lvalue refering to the object i. -// Hence T is deduced as int& val is int& && . -// any change on val changes the object i. -//! -//! Exercise 16.44: -//! Using the same three calls as in the first exercise, determine the types for T -//! if g’s function parameter is declared as T (not T&&). -// ^ -// g(i); -- T is deduced as int -// g(ci); -- T is deduced as int, const is ignored. -// g(i * ci); -- T is deduced as int, (i * ci) returns rvalue which is copied to -// T -//! What if g’s function parameter is const T&? -// ^^^^^^^^ -// g(i) -- T is deduced as int , val : const int& -// g(ci) -- T is deduced as int , val : const int& -// g(i * ci) -- T is deduced as int&&, val : const int&& & collapse to const int& -//! -//! Exercise 16.45: -//! Given the following template, explain what happens if we call g on a literal value -//! such as 42. What if we call g on a variable of type int? -//! template void g(T&& val) { vector v; } -//! -//! Discussion on SO: -// http://stackoverflow.com/questions/21624016/when-a-lvalue-is-passed-to-t-what-will-happen -//! -//! relevant section from textbook: -//! When we pass an lvalue (e.g., i) to a function parameter that is an rvalue reference to a -//! template type parameter (e.g, T&&), the compiler deduces the template type parameter as the -//! argument’s lvalue reference type. So, when we call f3(i), the compiler deduces the type of -//! T as int&, not int. -//! -- P.688 -//! -//! In this case, when calling on a literal value,say 42. int&& && will collapse to int&&. At last -//! T is deduced as int. Hence std::vector is instantiated as std::vector which is legal. -//! -//! When calling on a variable int. T will be deduced as int&. int & && will collapse to int&. -//! std::vector is not legal. The reason why int& can't be element of a vector can be found at: -// http://stackoverflow.com/questions/922360/why-cant-i-make-a-vector-of-references -//! -//! Exercise 16.46: -//! Explain this loop from StrVec::reallocate in § 13.5 (p. 530): -//! -//! for (size_t i = 0; i != size(); ++i) -//! alloc.construct(dest++, std::move(*elem++)); -//! -//! In each iteration, the dereference operator * returns a lvalue which is changed to rvalue by -//! std::move ,becasue the member function construct takes rvalue reference rather than lvalue -//! reference. -//! - - - - -#include -#include -#include - -template -void g(T&& val) -{ - std::vector v; -} - -int main() -{ - std::allocator a; - a.construct -} diff --git a/ch16/ex16.47/main.cpp b/ch16/ex16.47/main.cpp deleted file mode 100644 index 926c87ce..00000000 --- a/ch16/ex16.47/main.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/*************************************************************************** - * @file main.cpp - * @author Alan.W - * @date 07 Feb 2014 - * @remark This code is for the exercises from C++ Primer 5th Edition - * @note - ***************************************************************************/ -//! -//! Exercise 16.47: -//! Write your own version of the flip function -//! and test it by calling functions that have lvalue and rvalue reference parameters. -//! - -#include -#include - -void func_lvalue(std::string& lhs, std::string& rhs) -{ - lhs = "Wang\n"; - rhs = "Alan\n"; -} - -void func_rvalue(int&& lhs, int&& rhs) -{ - //! allocate enough space - std::allocator alloc; - int* data(alloc.allocate(3)); - - //! move into the spaced newly allocated - alloc.construct(data , lhs); - alloc.construct(data +1 , 0); - alloc.construct(data +2 , rhs); - - //! print - for (auto p = data; p != data + 3; ++p) - std::cout << *p << "\n"; - - //! destroy and deallocation - for (auto p = data +3; p != data; ) - alloc.destroy(--p); - alloc.deallocate(data,3); -} - -template -void flip(F f, T1&& t1, T2&& t2) -{ - f(std::forward(t2), std::forward(t1)); -} - -int main() -{ - //! test for lvalue reference - /* - std::string s1, s2; - flip(func_lvalue, s1, s2); - std::cout << s1 << s2; - */ - - //! test for rvalue reference - flip(func_rvalue, 99,88); - - -} diff --git a/ch16/ex16_47_flip.cpp b/ch16/ex16_47_flip.cpp new file mode 100644 index 00000000..f684f88f --- /dev/null +++ b/ch16/ex16_47_flip.cpp @@ -0,0 +1,24 @@ +#include + +void f(int v1, int& v2) +{ + std::cout << v1 << " " << ++v2 << std::endl; +} + +void g(int&& i, int& j) +{ + std::cout << i << " " << ++j << std::endl; +} + +template +void flip(F f, T1&& t1, T2&& t2) +{ + f(std::forward(t2), std::forward(t1)); +} + +int main() +{ + int j = 0; + flip(f, j, 42); + flip(g, j, 42); +} \ No newline at end of file From 93c4d8c2e78ef29dddeb18fee21fd46b9b644096 Mon Sep 17 00:00:00 2001 From: pezy chen Date: Fri, 25 May 2018 23:27:03 +0800 Subject: [PATCH 11/11] Fixed #141 --- ch02/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ch02/README.md b/ch02/README.md index f467990b..35d98041 100644 --- a/ch02/README.md +++ b/ch02/README.md @@ -560,7 +560,7 @@ auto a = i; decltype(i) b = i; // different auto c = r; -decltype(r) d = i; +decltype(r) d = r; ``` More? check [here](http://stackoverflow.com/questions/21369113/what-is-the-difference-between-auto-and-decltypeauto-when-returning-from-a-fun) and [here](http://stackoverflow.com/questions/12084040/decltype-vs-auto)