├── .gitignore ├── LICENSE ├── README.md ├── ch1 ├── 1.1.cpp ├── 1.10.cpp ├── 1.11.cpp ├── 1.12.md ├── 1.13.cpp ├── 1.14.md ├── 1.15.cpp ├── 1.16.cpp ├── 1.17.md ├── 1.18.cpp ├── 1.19.cpp ├── 1.2.cpp ├── 1.20.cpp ├── 1.20.in ├── 1.21.cpp ├── 1.21.in ├── 1.22.cpp ├── 1.22.in ├── 1.23.cpp ├── 1.23.in ├── 1.24.md ├── 1.25.cpp ├── 1.25.in ├── 1.3.cpp ├── 1.4.cpp ├── 1.5.cpp ├── 1.6.md ├── 1.7.cpp ├── 1.8.cpp ├── 1.9.cpp ├── Sales_item.h └── Version_test.h ├── ch10 ├── 10.1.cpp ├── 10.10.md ├── 10.11.cpp ├── 10.12.cpp ├── 10.12.in ├── 10.13.cpp ├── 10.14.cpp ├── 10.15.cpp ├── 10.16.cpp ├── 10.17.cpp ├── 10.17.in ├── 10.18.cpp ├── 10.19.cpp ├── 10.2.cpp ├── 10.20.cpp ├── 10.21.cpp ├── 10.22.cpp ├── 10.23.md ├── 10.24.cpp ├── 10.25.cpp ├── 10.26.md ├── 10.27.cpp ├── 10.28.cpp ├── 10.29.cpp ├── 10.3.cpp ├── 10.30.cpp ├── 10.31.cpp ├── 10.32.cpp ├── 10.32.in ├── 10.33.cpp ├── 10.33.in ├── 10.34.cpp ├── 10.35.cpp ├── 10.36.cpp ├── 10.37.cpp ├── 10.38.md ├── 10.39.md ├── 10.4.cpp ├── 10.40.md ├── 10.41.md ├── 10.42.cpp ├── 10.5.cpp ├── 10.6.cpp ├── 10.7.md ├── 10.8.md ├── 10.9.cpp ├── Sales_item.h └── Version_test.h ├── ch11 ├── 11.1.md ├── 11.10.md ├── 11.11.md ├── 11.12.cpp ├── 11.13.md ├── 11.14.cpp ├── 11.15.md ├── 11.16.cpp ├── 11.17.md ├── 11.18.md ├── 11.19.md ├── 11.2.md ├── 11.20.cpp ├── 11.21.md ├── 11.22.md ├── 11.23.cpp ├── 11.24.md ├── 11.25.md ├── 11.26.md ├── 11.27.md ├── 11.28.md ├── 11.29.md ├── 11.3.cpp ├── 11.30.md ├── 11.31.cpp ├── 11.32.md ├── 11.33.cpp ├── 11.33.dict.in ├── 11.33.text.in ├── 11.34.md ├── 11.35.md ├── 11.36.dict.in ├── 11.36.md ├── 11.37.md ├── 11.38.1.cpp ├── 11.38.2.cpp ├── 11.4.cpp ├── 11.4.in ├── 11.5.md ├── 11.6.md ├── 11.7.cpp ├── 11.8.cpp └── 11.9.cpp ├── ch12 ├── 12.1.md ├── 12.10.md ├── 12.11.md ├── 12.12.cpp ├── 12.13.md ├── 12.14.cpp ├── 12.15.cpp ├── 12.16.cpp ├── 12.17.cpp ├── 12.18.md ├── 12.19 │ ├── 12.19.cpp │ ├── StrBlob.cpp │ ├── StrBlob.h │ ├── StrBlobPtr.cpp │ └── StrBlobPtr.h ├── 12.2.cpp ├── 12.20 │ ├── 12.20.cpp │ ├── StrBlob.cpp │ ├── StrBlob.h │ ├── StrBlobPtr.cpp │ └── StrBlobPtr.h ├── 12.21.md ├── 12.22 │ ├── 12.22.cpp │ ├── ConstStrBlobPtr.cpp │ ├── ConstStrBlobPtr.h │ ├── StrBlob.cpp │ ├── StrBlob.h │ ├── StrBlobPtr.cpp │ └── StrBlobPtr.h ├── 12.23.cpp ├── 12.24.cpp ├── 12.25.md ├── 12.26.cpp ├── 12.27 │ ├── 12.27.cpp │ ├── 12.27.in │ ├── QueryResult.cpp │ ├── QueryResult.h │ ├── TextQuery.cpp │ └── TextQuery.h ├── 12.28.cpp ├── 12.29.cpp ├── 12.3.md ├── 12.30 │ ├── 12.30.cpp │ ├── 12.30.in │ ├── QueryResult.cpp │ ├── QueryResult.h │ ├── TextQuery.cpp │ └── TextQuery.h ├── 12.31.md ├── 12.32 │ ├── 12.32.cpp │ ├── 12.32.in │ ├── ConstStrBlobPtr.cpp │ ├── ConstStrBlobPtr.h │ ├── QueryResult.cpp │ ├── QueryResult.h │ ├── StrBlob.cpp │ ├── StrBlob.h │ ├── StrBlobPtr.cpp │ ├── StrBlobPtr.h │ ├── TextQuery.cpp │ └── TextQuery.h ├── 12.33 │ ├── 12.33.cpp │ ├── 12.33.in │ ├── ConstStrBlobPtr.cpp │ ├── ConstStrBlobPtr.h │ ├── QueryResult.cpp │ ├── QueryResult.h │ ├── StrBlob.cpp │ ├── StrBlob.h │ ├── StrBlobPtr.cpp │ ├── StrBlobPtr.h │ ├── TextQuery.cpp │ └── TextQuery.h ├── 12.4.md ├── 12.5.md ├── 12.6.cpp ├── 12.7.cpp ├── 12.8.md └── 12.9.md ├── ch13 ├── 13.1.md ├── 13.10.md ├── 13.11.cpp ├── 13.12.md ├── 13.13.cpp ├── 13.14.cpp ├── 13.15.cpp ├── 13.16.cpp ├── 13.17.md ├── 13.18.cpp ├── 13.19.cpp ├── 13.2.md ├── 13.20.md ├── 13.21.md ├── 13.22.md ├── 13.23.cpp ├── 13.24.md ├── 13.25.md ├── 13.26 │ ├── 13.26.cpp │ ├── ConstStrBlobPtr.cpp │ ├── ConstStrBlobPtr.h │ ├── StrBlob.cpp │ ├── StrBlob.h │ ├── StrBlobPtr.cpp │ └── StrBlobPtr.h ├── 13.27.cpp ├── 13.28.cpp ├── 13.29.md ├── 13.3.md ├── 13.30.cpp ├── 13.31.cpp ├── 13.32.md ├── 13.33.md ├── 13.34.cpp ├── 13.35.md ├── 13.36.cpp ├── 13.37.cpp ├── 13.38.md ├── 13.39 │ ├── 13.39.cpp │ ├── StrVec.cpp │ └── StrVec.h ├── 13.4.md ├── 13.40 │ ├── 13.40.cpp │ ├── StrVec.cpp │ └── StrVec.h ├── 13.41.md ├── 13.42 │ ├── 13.42.cpp │ ├── 13.42.in │ ├── QueryResult.cpp │ ├── QueryResult.h │ ├── StrVec.cpp │ ├── StrVec.h │ ├── TextQuery.cpp │ └── TextQuery.h ├── 13.43 │ ├── 13.43.cpp │ ├── StrVec.cpp │ └── StrVec.h ├── 13.44 │ ├── 13.44.cpp │ ├── String.cpp │ └── String.h ├── 13.45.md ├── 13.46.cpp ├── 13.47 │ ├── 13.47.cpp │ ├── String.cpp │ └── String.h ├── 13.48.md ├── 13.49 │ ├── Message.cpp │ ├── StrVec.cpp │ ├── StrVec.h │ ├── String.cpp │ ├── String.h │ ├── TestStrVec.cpp │ └── TestString.cpp ├── 13.5.cpp ├── 13.50.md ├── 13.51.md ├── 13.52.md ├── 13.53.cpp ├── 13.54.cpp ├── 13.55 │ ├── 13.55.cpp │ ├── ConstStrBlobPtr.cpp │ ├── ConstStrBlobPtr.h │ ├── StrBlob.cpp │ ├── StrBlob.h │ ├── StrBlobPtr.cpp │ └── StrBlobPtr.h ├── 13.56.cpp ├── 13.57.md ├── 13.58.md ├── 13.6.md ├── 13.7.md ├── 13.8.cpp └── 13.9.md ├── ch14 ├── 14.1.md ├── 14.10.md ├── 14.11.md ├── 14.12.md ├── 14.13.cpp ├── 14.14.md ├── 14.15.md ├── 14.16 │ ├── StrBlob │ │ ├── ConstStrBlobPtr.cpp │ │ ├── ConstStrBlobPtr.h │ │ ├── StrBlob.cpp │ │ ├── StrBlob.h │ │ ├── StrBlobPtr.cpp │ │ ├── StrBlobPtr.h │ │ └── TestStrBlob.cpp │ ├── StrVec │ │ ├── StrVec.cpp │ │ ├── StrVec.h │ │ └── TestStrVec.cpp │ └── String │ │ ├── String.cpp │ │ ├── String.h │ │ └── TestString.cpp ├── 14.17.md ├── 14.18 │ ├── StrBlob │ │ ├── ConstStrBlobPtr.cpp │ │ ├── ConstStrBlobPtr.h │ │ ├── StrBlob.cpp │ │ ├── StrBlob.h │ │ ├── StrBlobPtr.cpp │ │ ├── StrBlobPtr.h │ │ └── TestStrBlob.cpp │ ├── StrVec │ │ ├── StrVec.cpp │ │ ├── StrVec.h │ │ └── TestStrVec.cpp │ └── String │ │ ├── String.cpp │ │ ├── String.h │ │ └── TestString.cpp ├── 14.19.md ├── 14.2.cpp ├── 14.20.md ├── 14.21.cpp ├── 14.22.cpp ├── 14.23 │ ├── StrVec.cpp │ ├── StrVec.h │ └── TestStrVec.cpp ├── 14.24.md ├── 14.25.md ├── 14.26 │ ├── StrBlob │ │ ├── ConstStrBlobPtr.cpp │ │ ├── ConstStrBlobPtr.h │ │ ├── StrBlob.cpp │ │ ├── StrBlob.h │ │ ├── StrBlobPtr.cpp │ │ ├── StrBlobPtr.h │ │ └── TestStrBlob.cpp │ ├── StrVec │ │ ├── StrVec.cpp │ │ ├── StrVec.h │ │ └── TestStrVec.cpp │ └── String │ │ ├── String.cpp │ │ ├── String.h │ │ └── TestString.cpp ├── 14.27 │ ├── ConstStrBlobPtr.cpp │ ├── ConstStrBlobPtr.h │ ├── StrBlob.cpp │ ├── StrBlob.h │ ├── StrBlobPtr.cpp │ ├── StrBlobPtr.h │ └── TestStrBlob.cpp ├── 14.28 │ ├── ConstStrBlobPtr.cpp │ ├── ConstStrBlobPtr.h │ ├── StrBlob.cpp │ ├── StrBlob.h │ ├── StrBlobPtr.cpp │ ├── StrBlobPtr.h │ └── TestStrBlob.cpp ├── 14.29.md ├── 14.3.md ├── 14.30 │ ├── ConstStrBlobPtr.cpp │ ├── ConstStrBlobPtr.h │ ├── StrBlob.cpp │ ├── StrBlob.h │ ├── StrBlobPtr.cpp │ ├── StrBlobPtr.h │ └── TestStrBlob.cpp ├── 14.31.md ├── 14.32 │ ├── ConstStrBlobPtr.cpp │ ├── ConstStrBlobPtr.h │ ├── StrBlob.cpp │ ├── StrBlob.h │ ├── StrBlobPtr.cpp │ ├── StrBlobPtr.h │ └── TestStrBlob.cpp ├── 14.33.md ├── 14.34.cpp ├── 14.35.cpp ├── 14.36.md ├── 14.37.cpp ├── 14.38.cpp ├── 14.38.in ├── 14.39.cpp ├── 14.4.md ├── 14.40.cpp ├── 14.41.md ├── 14.42.cpp ├── 14.43.cpp ├── 14.44.cpp ├── 14.45.cpp ├── 14.46.md ├── 14.47.md ├── 14.48.md ├── 14.49.md ├── 14.5.md ├── 14.50.cpp ├── 14.51.cpp ├── 14.52.cpp ├── 14.53.cpp ├── 14.6.cpp ├── 14.7 │ ├── 14.7.cpp │ ├── String.cpp │ └── String.h ├── 14.8.md └── 14.9.cpp ├── ch15 ├── 15.1.md ├── 15.10.md ├── 15.11.cpp ├── 15.12.md ├── 15.13.md ├── 15.14.cpp ├── 15.15.cpp ├── 15.16.md ├── 15.17.cpp ├── 15.18.cpp ├── 15.19.cpp ├── 15.2.md ├── 15.20.md ├── 15.21.cpp ├── 15.22.cpp ├── 15.23.cpp ├── 15.24.md ├── 15.25.md ├── 15.26.cpp ├── 15.27.cpp ├── 15.28.cpp ├── 15.29.cpp ├── 15.3.cpp ├── 15.30.cpp ├── 15.31.md ├── 15.32.md ├── 15.33.md ├── 15.34.md ├── 15.35 │ ├── AndQuery.cpp │ ├── AndQuery.h │ ├── BinaryQuery.h │ ├── NotQuery.cpp │ ├── NotQuery.h │ ├── OrQuery.cpp │ ├── OrQuery.h │ ├── Query.cpp │ ├── Query.h │ ├── QueryResult.cpp │ ├── QueryResult.h │ ├── Query_base.h │ ├── StrVec.cpp │ ├── StrVec.h │ ├── TestQuery.cpp │ ├── TestTextQuery.cpp │ ├── TextQuery.cpp │ ├── TextQuery.h │ ├── WordQuery.h │ └── text.in ├── 15.36.md ├── 15.37 │ ├── AndQuery.cpp │ ├── AndQuery.h │ ├── BinaryQuery.h │ ├── NotQuery.cpp │ ├── NotQuery.h │ ├── OrQuery.cpp │ ├── OrQuery.h │ ├── Query.cpp │ ├── Query.h │ ├── QueryResult.cpp │ ├── QueryResult.h │ ├── Query_base.h │ ├── StrVec.cpp │ ├── StrVec.h │ ├── TestQuery.cpp │ ├── TestTextQuery.cpp │ ├── TextQuery.cpp │ ├── TextQuery.h │ ├── WordQuery.h │ └── text.in ├── 15.38.md ├── 15.39 │ ├── AndQuery.cpp │ ├── AndQuery.h │ ├── BinaryQuery.h │ ├── NotQuery.cpp │ ├── NotQuery.h │ ├── OrQuery.cpp │ ├── OrQuery.h │ ├── Query.cpp │ ├── Query.h │ ├── QueryResult.cpp │ ├── QueryResult.h │ ├── Query_base.h │ ├── StrVec.cpp │ ├── StrVec.h │ ├── TestQuery.cpp │ ├── TestTextQuery.cpp │ ├── TextQuery.cpp │ ├── TextQuery.h │ ├── WordQuery.h │ └── text.in ├── 15.4.md ├── 15.40.md ├── 15.41 │ ├── AndQuery.cpp │ ├── AndQuery.h │ ├── BinaryQuery.h │ ├── NotQuery.cpp │ ├── NotQuery.h │ ├── OrQuery.cpp │ ├── OrQuery.h │ ├── Query.cpp │ ├── Query.h │ ├── QueryResult.cpp │ ├── QueryResult.h │ ├── Query_base.h │ ├── StrVec.cpp │ ├── StrVec.h │ ├── TestQuery.cpp │ ├── TestTextQuery.cpp │ ├── TextQuery.cpp │ ├── TextQuery.h │ ├── WordQuery.h │ └── text.in ├── 15.5.md ├── 15.6.md ├── 15.7.cpp ├── 15.8.md └── 15.9.md ├── ch16 ├── 16.1.md ├── 16.10.md ├── 16.11.cpp ├── 16.12 │ ├── Blob.h │ ├── BlobPtr.h │ ├── ConstBlobPtr.h │ └── TestBlob.cpp ├── 16.13.md ├── 16.14.cpp ├── 16.15.md ├── 16.16 │ ├── TestVec.cpp │ └── Vec.h ├── 16.17.md ├── 16.18.cpp ├── 16.19.cpp ├── 16.2.cpp ├── 16.20.cpp ├── 16.21.cpp ├── 16.22 │ ├── AndQuery.cpp │ ├── AndQuery.h │ ├── BinaryQuery.h │ ├── DebugDelete.h │ ├── NotQuery.cpp │ ├── NotQuery.h │ ├── OrQuery.cpp │ ├── OrQuery.h │ ├── Query.cpp │ ├── Query.h │ ├── QueryResult.cpp │ ├── QueryResult.h │ ├── Query_base.h │ ├── StrVec.cpp │ ├── StrVec.h │ ├── TestQuery.cpp │ ├── TestTextQuery.cpp │ ├── TextQuery.cpp │ ├── TextQuery.h │ ├── WordQuery.h │ └── text.in ├── 16.23.md ├── 16.24 │ ├── Blob.h │ ├── BlobPtr.h │ ├── ConstBlobPtr.h │ └── TestBlob.cpp ├── 16.25.md ├── 16.26.md ├── 16.27.cpp ├── 16.3.cpp ├── 16.4.cpp ├── 16.5.cpp ├── 16.6.cpp ├── 16.7.cpp ├── 16.8.md └── 16.9.md ├── ch2 ├── 2.1.md ├── 2.10.cpp ├── 2.11.cpp ├── 2.12.cpp ├── 2.13.cpp ├── 2.14.cpp ├── 2.15.cpp ├── 2.16.cpp ├── 2.17.cpp ├── 2.18.cpp ├── 2.19.md ├── 2.2.md ├── 2.20.cpp ├── 2.21.cpp ├── 2.22.md ├── 2.23.md ├── 2.24.cpp ├── 2.25.cpp ├── 2.26.cpp ├── 2.27.cpp ├── 2.28.cpp ├── 2.29.cpp ├── 2.3.md ├── 2.30.cpp ├── 2.31.cpp ├── 2.32.cpp ├── 2.33.md ├── 2.34.cpp ├── 2.35.cpp ├── 2.36.cpp ├── 2.37.cpp ├── 2.38.md ├── 2.39.cpp ├── 2.4.cpp ├── 2.40.cpp ├── 2.41.cpp ├── 2.42.cpp ├── 2.5.cpp ├── 2.6.cpp ├── 2.7.cpp ├── 2.8.cpp ├── 2.9.cpp └── Sales_data.h ├── ch3 ├── 3.1.cpp ├── 3.10.cpp ├── 3.11.md ├── 3.12.cpp ├── 3.13.cpp ├── 3.14.cpp ├── 3.15.cpp ├── 3.15.in ├── 3.16.cpp ├── 3.17.cpp ├── 3.17.in ├── 3.18.md ├── 3.19.cpp ├── 3.2.cpp ├── 3.20.cpp ├── 3.21.cpp ├── 3.22.cpp ├── 3.22.in ├── 3.23.cpp ├── 3.24.cpp ├── 3.25.cpp ├── 3.26.md ├── 3.27.cpp ├── 3.28.cpp ├── 3.29.md ├── 3.3.md ├── 3.30.cpp ├── 3.31.cpp ├── 3.32.cpp ├── 3.33.md ├── 3.34.md ├── 3.35.cpp ├── 3.36.cpp ├── 3.37.md ├── 3.38.md ├── 3.39.cpp ├── 3.4.cpp ├── 3.40.cpp ├── 3.41.cpp ├── 3.42.cpp ├── 3.43.cpp ├── 3.44.cpp ├── 3.45.cpp ├── 3.5.cpp ├── 3.5.in ├── 3.6.cpp ├── 3.7.cpp ├── 3.8.cpp └── 3.9.cpp ├── ch4 ├── 4.1.cpp ├── 4.10.cpp ├── 4.11.cpp ├── 4.12.md ├── 4.13.cpp ├── 4.14.md ├── 4.15.cpp ├── 4.16.md ├── 4.17.md ├── 4.18.md ├── 4.19.md ├── 4.2.md ├── 4.20.md ├── 4.21.cpp ├── 4.22.cpp ├── 4.23.cpp ├── 4.24.md ├── 4.25.md ├── 4.26.md ├── 4.27.cpp ├── 4.28.cpp ├── 4.29.cpp ├── 4.3.md ├── 4.30.md ├── 4.31.cpp ├── 4.32.cpp ├── 4.33.md ├── 4.34.md ├── 4.35.cpp ├── 4.36.cpp ├── 4.37.cpp ├── 4.38.md ├── 4.4.cpp ├── 4.5.cpp ├── 4.6.cpp ├── 4.7.cpp ├── 4.8.md └── 4.9.md ├── ch5 ├── 5.1.md ├── 5.10.cpp ├── 5.11.cpp ├── 5.11.in ├── 5.12.cpp ├── 5.13.md ├── 5.14.cpp ├── 5.15.md ├── 5.16.cpp ├── 5.17.cpp ├── 5.18.md ├── 5.19.cpp ├── 5.2.md ├── 5.20.cpp ├── 5.21.cpp ├── 5.22.md ├── 5.23.cpp ├── 5.24.cpp ├── 5.25.cpp ├── 5.3.cpp ├── 5.4.md ├── 5.5.cpp ├── 5.6.cpp ├── 5.7.md ├── 5.8.md └── 5.9.cpp ├── ch6 ├── 6.1.md ├── 6.10.cpp ├── 6.11.cpp ├── 6.12.cpp ├── 6.13.md ├── 6.14.md ├── 6.15.md ├── 6.16.md ├── 6.17.cpp ├── 6.18.md ├── 6.19.md ├── 6.2.md ├── 6.20.md ├── 6.21.cpp ├── 6.22.cpp ├── 6.23.cpp ├── 6.24.md ├── 6.25.cpp ├── 6.26.cpp ├── 6.27.cpp ├── 6.28.md ├── 6.29.md ├── 6.3.cpp ├── 6.30.cpp ├── 6.31.md ├── 6.32.cpp ├── 6.33.cpp ├── 6.34.md ├── 6.35.md ├── 6.36.cpp ├── 6.37.cpp ├── 6.38.cpp ├── 6.39.md ├── 6.4.cpp ├── 6.40.md ├── 6.41.md ├── 6.42.cpp ├── 6.43.md ├── 6.44.cpp ├── 6.45.cpp ├── 6.46.md ├── 6.47.cpp ├── 6.48.md ├── 6.49.md ├── 6.5.cpp ├── 6.50.md ├── 6.51.cpp ├── 6.52.md ├── 6.53.md ├── 6.54.cpp ├── 6.55.cpp ├── 6.56.md ├── 6.6.md ├── 6.7.cpp ├── 6.8 │ └── Chapter6.h └── 6.9 │ ├── Chapter6.h │ ├── fact.cc │ └── factMain.cc ├── ch7 ├── 7.1.cpp ├── 7.10.md ├── 7.11.cpp ├── 7.12.cpp ├── 7.13.cpp ├── 7.14.cpp ├── 7.15.cpp ├── 7.16.md ├── 7.17.md ├── 7.18.md ├── 7.19.cpp ├── 7.2.cpp ├── 7.20.md ├── 7.21.cpp ├── 7.22.cpp ├── 7.23.cpp ├── 7.24.md ├── 7.25.md ├── 7.26.cpp ├── 7.27.cpp ├── 7.28.md ├── 7.29.cpp ├── 7.3.cpp ├── 7.30.md ├── 7.31.cpp ├── 7.32.cpp ├── 7.33.md ├── 7.34.md ├── 7.35.cpp ├── 7.36.md ├── 7.37.md ├── 7.38.cpp ├── 7.39.md ├── 7.4.cpp ├── 7.40.md ├── 7.41.cpp ├── 7.42.md ├── 7.43.cpp ├── 7.44.md ├── 7.45.md ├── 7.46.md ├── 7.47.md ├── 7.48.md ├── 7.49.md ├── 7.5.cpp ├── 7.50.cpp ├── 7.51.md ├── 7.52.cpp ├── 7.53.cpp ├── 7.54.md ├── 7.55.md ├── 7.56.md ├── 7.57.cpp ├── 7.58.md ├── 7.6.cpp ├── 7.7.cpp ├── 7.8.md └── 7.9.cpp ├── ch8 ├── 8.1.cpp ├── 8.10.cpp ├── 8.11.cpp ├── 8.12.md ├── 8.13.cpp ├── 8.13.in ├── 8.14.md ├── 8.2.md ├── 8.3.md ├── 8.4.cpp ├── 8.5.cpp ├── 8.6.cpp ├── 8.6.in ├── 8.7.cpp ├── 8.7.in ├── 8.8.cpp ├── 8.8.in └── 8.9.cpp └── ch9 ├── 9.1.md ├── 9.10.md ├── 9.11.cpp ├── 9.12.md ├── 9.13.cpp ├── 9.14.cpp ├── 9.15.cpp ├── 9.16.cpp ├── 9.17.md ├── 9.18.cpp ├── 9.19.cpp ├── 9.2.cpp ├── 9.20.cpp ├── 9.21.md ├── 9.22.md ├── 9.23.md ├── 9.24.cpp ├── 9.25.md ├── 9.26.cpp ├── 9.27.cpp ├── 9.28.cpp ├── 9.29.md ├── 9.3.md ├── 9.30.md ├── 9.31.cpp ├── 9.32.md ├── 9.33.cpp ├── 9.34.cpp ├── 9.35.md ├── 9.36.md ├── 9.37.md ├── 9.38.cpp ├── 9.39.md ├── 9.4.cpp ├── 9.40.md ├── 9.41.cpp ├── 9.42.md ├── 9.43.cpp ├── 9.44.cpp ├── 9.45.cpp ├── 9.46.cpp ├── 9.47.cpp ├── 9.48.cpp ├── 9.49.cpp ├── 9.5.cpp ├── 9.50.cpp ├── 9.51.cpp ├── 9.52.cpp ├── 9.6.md ├── 9.7.md ├── 9.8.md └── 9.9.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | 30 | # Temporary files 31 | *.swp 32 | -------------------------------------------------------------------------------- /ch1/1.1.cpp: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 0; 3 | } 4 | -------------------------------------------------------------------------------- /ch1/1.10.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int val = 10; 5 | while (val >= 0) 6 | std::cout << val-- << " "; 7 | std::cout << std::endl; 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /ch1/1.11.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int bg = 0, ed = 0; 5 | std::cout << "Enter the number of begin and end: "; 6 | std::cin >> bg >> ed; 7 | while (bg <= ed) 8 | std::cout << bg++ << " "; 9 | std::cout << std::endl; 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /ch1/1.12.md: -------------------------------------------------------------------------------- 1 | The loop add all numbers from -100 to 100 inclusive. The value of `sum` is 0. 2 | -------------------------------------------------------------------------------- /ch1/1.13.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | // Rewrite ex1.9 5 | int sum = 0; 6 | for (int i = 50; i <= 100; ++i) 7 | sum += i; 8 | std::cout << "Sum of 50 to 100 inclusive is " 9 | << sum << std::endl; 10 | 11 | // Rewrite ex1.10 12 | for (int val = 10; val >= 0; --val) 13 | std::cout << val << " "; 14 | std::cout << std::endl; 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /ch1/1.14.md: -------------------------------------------------------------------------------- 1 | `for` has a scope where you can define temporary variables and used inside loop. 2 | 3 | `while` is simple and apporiate for situations where the loop time is unknown before the loop. 4 | -------------------------------------------------------------------------------- /ch1/1.15.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | int main( { 3 | std::cout << "Read each file." << std::endl: 4 | std::cout << Update master. << std::endl; 5 | std::cout << "Write new master." std::endl; 6 | return 0 7 | } 8 | -------------------------------------------------------------------------------- /ch1/1.16.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | std::cout << "Enter numbers:" << std::endl; 5 | int sum = 0, val = 0; 6 | while (std::cin >> val) 7 | sum += val; 8 | std::cout << "The sum of numbers is " << sum << std::endl; 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /ch1/1.17.md: -------------------------------------------------------------------------------- 1 | See [ex1.18](1.18.cpp). 2 | -------------------------------------------------------------------------------- /ch1/1.18.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int curVal = 0, val = 0; 5 | if (std::cin >> curVal) { 6 | int cnt = 1; 7 | while (std::cin >> val) { 8 | if (val == curVal) 9 | ++cnt; 10 | else { 11 | std::cout << curVal << " occurs " 12 | << cnt << " time(s)" << std::endl; 13 | curVal = val; 14 | cnt = 1; 15 | } 16 | } 17 | std::cout << curVal << " occurs " 18 | << cnt << " time(s)" << std::endl; 19 | } 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /ch1/1.19.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int bg = 0, ed = 0; 5 | std::cout << "Enter the number of begin and end: "; 6 | std::cin >> bg >> ed; 7 | while (bg <= ed) 8 | std::cout << bg++ << " "; 9 | std::cout << std::endl; 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /ch1/1.2.cpp: -------------------------------------------------------------------------------- 1 | int main() { 2 | return -1; 3 | } 4 | -------------------------------------------------------------------------------- /ch1/1.20.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Sales_item.h" 3 | 4 | int main() { 5 | Sales_item item; 6 | while (std::cin >> item) 7 | std::cout << item << std::endl; 8 | 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /ch1/1.20.in: -------------------------------------------------------------------------------- 1 | 0-201-12345-X 3 20.00 2 | 0-202-12345-X 2 25.50 3 | 0-203-12345-X 4 10.00 4 | 0-204-12345-X 1 40.00 5 | 0-205-12345-X 6 2.00 6 | -------------------------------------------------------------------------------- /ch1/1.21.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Sales_item.h" 3 | 4 | int main() { 5 | Sales_item item1, item2; 6 | std::cin >> item1 >> item2; 7 | std::cout << item1 + item2 << std::endl; 8 | 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /ch1/1.21.in: -------------------------------------------------------------------------------- 1 | 0-201-12345-X 3 20.00 2 | 0-201-12345-X 2 25.50 3 | -------------------------------------------------------------------------------- /ch1/1.22.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Sales_item.h" 3 | 4 | int main() { 5 | Sales_item total, item; 6 | if (std::cin >> total) { 7 | while (std::cin >> item) 8 | total += item; 9 | std::cout << total << std::endl; 10 | } 11 | 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /ch1/1.22.in: -------------------------------------------------------------------------------- 1 | 0-201-12345-X 3 20.00 2 | 0-201-12345-X 2 25.50 3 | 0-201-12345-X 4 10.00 4 | 0-201-12345-X 1 40.00 5 | 0-201-12345-X 6 8.00 6 | -------------------------------------------------------------------------------- /ch1/1.23.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Sales_item.h" 3 | 4 | int main() { 5 | Sales_item curItem, item; 6 | if (std::cin >> curItem) { 7 | int cnt = 1; 8 | while (std::cin >> item) { 9 | if (item.isbn() == curItem.isbn()) 10 | ++cnt; 11 | else { 12 | std::cout << curItem.isbn() << " " << cnt << std::endl; 13 | curItem = item; 14 | cnt = 1; 15 | } 16 | } 17 | std::cout << curItem.isbn() << " " << cnt << std::endl; 18 | } 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /ch1/1.23.in: -------------------------------------------------------------------------------- 1 | 0-201-12345-X 3 20.00 2 | 0-201-12345-X 4 20.00 3 | 0-201-12345-X 2 21.50 4 | 0-202-12345-X 2 25.50 5 | 0-203-12345-X 4 10.00 6 | 0-203-12345-X 5 13.00 7 | 0-204-12345-X 1 40.00 8 | 0-205-12345-X 6 2.00 9 | 0-205-12345-X 3 4.00 10 | 0-205-12345-X 5 3.00 11 | 0-206-12345-X 3 24.00 12 | -------------------------------------------------------------------------------- /ch1/1.24.md: -------------------------------------------------------------------------------- 1 | See [ex1.23](1.23.cpp). 2 | -------------------------------------------------------------------------------- /ch1/1.25.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Sales_item.h" 3 | 4 | int main() { 5 | Sales_item total; 6 | if (std::cin >> total) { 7 | Sales_item trans; 8 | while (std::cin >> trans) { 9 | if (total.isbn() == trans.isbn()) 10 | total += trans; 11 | else { 12 | std::cout << total << std::endl; 13 | total = trans; 14 | } 15 | } 16 | std::cout << total << std::endl; 17 | } else { 18 | std::cerr << "No data!" << std::endl; 19 | return -1; 20 | } 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /ch1/1.25.in: -------------------------------------------------------------------------------- 1 | 0-201-12345-X 3 20.00 2 | 0-201-12345-X 4 20.00 3 | 0-201-12345-X 2 21.50 4 | 0-202-12345-X 2 25.50 5 | 0-203-12345-X 4 10.00 6 | 0-203-12345-X 5 13.00 7 | 0-204-12345-X 1 40.00 8 | 0-205-12345-X 6 2.00 9 | 0-205-12345-X 3 4.00 10 | 0-205-12345-X 5 3.00 11 | 0-206-12345-X 3 24.00 12 | -------------------------------------------------------------------------------- /ch1/1.3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | int main() { 3 | std::cout << "Hello, World" << std::endl; 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /ch1/1.4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | int main() { 3 | std::cout << "Enter two numbers:" << std::endl; 4 | int x, y; 5 | std::cin >> x >> y; 6 | std::cout << "The product of " << x << " and " << y << " is " 7 | << x * y << std::endl; 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /ch1/1.5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | int main() { 3 | std::cout << "Enter two numbers:" << std::endl; 4 | int x = 0, y = 0; 5 | std::cin >> x >> y; 6 | std::cout << "The sum of " << x ; 7 | std::cout << " and " << y << " is "; 8 | std::cout << x + y << std::endl; 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /ch1/1.6.md: -------------------------------------------------------------------------------- 1 | The program is not legal. The operator `<<` is a member of `std::cout`, thus cannot be called without the object `std::cout`. Prepend the expression with `std::cout`. 2 | -------------------------------------------------------------------------------- /ch1/1.7.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Error comment: /* */ 3 | */ 4 | 5 | int main () { 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /ch1/1.8.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | std::cout << "/*"; // OK 5 | std::cout << "*/"; // OK 6 | std::cout << /* "*/" */; // Error 7 | std::cout << /* "*/" /* "/*" */; // OK 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /ch1/1.9.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int sum = 0, val = 50; 5 | while (val <= 100) { 6 | sum += val; 7 | ++val; 8 | } 9 | std::cout << "Sum of 50 to 100 inclusive is " 10 | << sum << std::endl; 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /ch10/10.1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | int val; 7 | std::cin >> val; 8 | std::vector vi; 9 | for (int i; std::cin >> i; vi.push_back(i)) {} 10 | std::cout << "Value \"" << val << "\" occours " 11 | << std::count(vi.begin(), vi.end(), val) << " time(s) in sequence." 12 | << std::endl; 13 | 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /ch10/10.10.md: -------------------------------------------------------------------------------- 1 | We pass only iterators to algorithms, not containers, so the algorithms have no direct access to the container members. If we want change the size of a container, we must do it by calling the cotainer members. Thus the algorithms cannot change the size of containers. 2 | 3 | Insert iterator, however, has access to container members when we pass the container to it. Thus it can change the size of containers. 4 | -------------------------------------------------------------------------------- /ch10/10.12.in: -------------------------------------------------------------------------------- 1 | 0-201-12345-X 3 20.00 2 | 0-205-12345-X 5 3.00 3 | 0-201-12345-X 2 20.00 4 | 0-202-12345-X 2 25.50 5 | 0-201-12345-X 3 20.00 6 | 0-201-12345-X 4 20.00 7 | 0-205-12345-X 6 2.00 8 | 0-201-12345-X 4 10.00 9 | 0-201-12345-X 1 40.00 10 | 0-205-12345-X 6 3.50 11 | 0-201-12345-X 6 8.00 12 | 0-201-12345-X 0 20.00 13 | 0-202-12345-X 2 25.50 14 | 0-203-12345-X 4 10.00 15 | 0-206-12345-X 3 24.00 16 | 0-201-12345-X 2 25.50 17 | 0-203-12345-X 4 10.00 18 | 0-204-12345-X 1 40.00 19 | 0-203-12345-X 5 13.00 20 | 0-201-12345-X 2 21.50 21 | 0-201-12345-X 2 25.50 22 | 0-205-12345-X 3 4.00 23 | -------------------------------------------------------------------------------- /ch10/10.13.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | bool longStr(const std::string &s) { 7 | return s.size() >= 5; 8 | } 9 | 10 | int main() { 11 | std::vector words; 12 | for (std::string s; std::cin >> s; words.push_back(s)) {} 13 | auto long_bg = std::partition(words.begin(), words.end(), longStr); 14 | for (auto it = words.begin(); it != long_bg; ++it) 15 | std::cout << *it << " "; 16 | std::cout << std::endl; 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /ch10/10.14.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | auto sum = [](int a, int b) { return a + b; }; 5 | 6 | int a, b; 7 | std::cin >> a >> b; 8 | std::cout << a << " + " << b << " = " << sum(a, b) << std::endl; 9 | 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /ch10/10.15.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int x, y; 5 | std::cin >> x >> y; 6 | auto sum = [x](int i) { return x + i; }; 7 | // The lamda must be defined after we read x, otherwise it will capture the 8 | // undefined value of x. 9 | std::cout << x << " + " << y << " = " << sum(y) << std::endl; 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /ch10/10.17.in: -------------------------------------------------------------------------------- 1 | 0-201-12345-X 3 20.00 2 | 0-205-12345-X 5 3.00 3 | 0-201-12345-X 2 20.00 4 | 0-202-12345-X 2 25.50 5 | 0-201-12345-X 3 20.00 6 | 0-201-12345-X 4 20.00 7 | 0-205-12345-X 6 2.00 8 | 0-201-12345-X 4 10.00 9 | 0-201-12345-X 1 40.00 10 | 0-205-12345-X 6 3.50 11 | 0-201-12345-X 6 8.00 12 | 0-201-12345-X 0 20.00 13 | 0-202-12345-X 2 25.50 14 | 0-203-12345-X 4 10.00 15 | 0-206-12345-X 3 24.00 16 | 0-201-12345-X 2 25.50 17 | 0-203-12345-X 4 10.00 18 | 0-204-12345-X 1 40.00 19 | 0-203-12345-X 5 13.00 20 | 0-201-12345-X 2 21.50 21 | 0-201-12345-X 2 25.50 22 | 0-205-12345-X 3 4.00 23 | -------------------------------------------------------------------------------- /ch10/10.2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | std::string val; 8 | std::cin >> val; 9 | std::list vi; 10 | for (std::string i; std::cin >> i; vi.push_back(i)) {} 11 | std::cout << "Value \"" << val << "\" occours " 12 | << std::count(vi.begin(), vi.end(), val) << " time(s) in sequence." 13 | << std::endl; 14 | 15 | // The only changes we made are the type of the variables, the function call 16 | // is still the same with ex10.1. 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /ch10/10.21.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int n; 5 | auto isZero = [&n] { return n > 0 ? --n, false : true; }; 6 | // Use comma expression to return bool value 7 | std::cin >> n; 8 | 9 | while (!isZero()) 10 | std::cout << n << std::endl; 11 | isZero(); 12 | std::cout << n << std::endl; 13 | //std::cout << typeid(isZero()).name() << std::endl; 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /ch10/10.23.md: -------------------------------------------------------------------------------- 1 | The number of arguments that `bind` takes depends on the callable it binds to. It is equal to how many arguments the original callable takes plus one (which is the original callable itself). 2 | -------------------------------------------------------------------------------- /ch10/10.26.md: -------------------------------------------------------------------------------- 1 | `back_inserter` always inserts element at the end of the container by calling `c.push_back()`. 2 | 3 | `front_inserter` always inserts element at the beginning of the container by calling `c.push_front()`. 4 | 5 | `inserter` always insert element at the front of the same given element in the container by calling `c.insert()`. 6 | -------------------------------------------------------------------------------- /ch10/10.27.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | std::vector vi; 9 | for (int i; std::cin >> i; vi.push_back(i)) {} 10 | std::list li; 11 | std::sort(vi.begin(), vi.end()); // This will change the original vector. 12 | std::unique_copy(vi.begin(), vi.end(), std::back_inserter(li)); 13 | std::for_each(li.begin(), li.end(), 14 | [](int i) { std::cout << i << " ";}); 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /ch10/10.29.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | std::string filename; 9 | std::cin >> filename; 10 | std::ifstream in(filename); 11 | if (!in.is_open()) { 12 | std::cerr << "Can not open file: " << filename << std::endl; 13 | return -1; 14 | } 15 | std::istream_iterator iter(in), eof; 16 | //std::vector vs; 17 | //while (iter != eof) 18 | // vs.push_back(*iter++); 19 | std::vector vs(iter, eof); // The shorter way 20 | for (const auto &s: vs) 21 | std::cout << s << std::endl; 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /ch10/10.3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::vector vi; 7 | for (int i; std::cin >> i; vi.push_back(i)) {} 8 | std::cout << "The sum of the sequence is " 9 | << std::accumulate(vi.cbegin(), vi.cend(), 0) << std::endl; 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /ch10/10.30.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | std::istream_iterator i_iter(std::cin), i_eof; 8 | //std::vector vi; 9 | //while (i_iter != i_eof) 10 | // vi.push_back(*i_iter++); 11 | std::vector vi(i_iter, i_eof); 12 | std::sort(vi.begin(), vi.end()); 13 | std::ostream_iterator o_iter(std::cout, " "); 14 | std::copy(vi.begin(), vi.end(), o_iter); 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /ch10/10.31.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | std::istream_iterator i_iter(std::cin), i_eof; 8 | std::vector vi(i_iter, i_eof); 9 | std::sort(vi.begin(), vi.end()); 10 | std::ostream_iterator o_iter(std::cout, " "); 11 | std::unique_copy(vi.begin(), vi.end(), o_iter); 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /ch10/10.32.in: -------------------------------------------------------------------------------- 1 | 0-201-12345-X 3 20.00 2 | 0-205-12345-X 5 3.00 3 | 0-201-12345-X 2 20.00 4 | 0-202-12345-X 2 25.50 5 | 0-201-12345-X 3 20.00 6 | 0-201-12345-X 4 20.00 7 | 0-205-12345-X 6 2.00 8 | 0-201-12345-X 4 10.00 9 | 0-201-12345-X 1 40.00 10 | 0-205-12345-X 6 3.50 11 | 0-201-12345-X 6 8.00 12 | 0-201-12345-X 0 20.00 13 | 0-202-12345-X 2 25.50 14 | 0-203-12345-X 4 10.00 15 | 0-206-12345-X 3 24.00 16 | 0-201-12345-X 2 25.50 17 | 0-203-12345-X 4 10.00 18 | 0-204-12345-X 1 40.00 19 | 0-203-12345-X 5 13.00 20 | 0-201-12345-X 2 21.50 21 | 0-201-12345-X 2 25.50 22 | 0-205-12345-X 3 4.00 23 | -------------------------------------------------------------------------------- /ch10/10.33.in: -------------------------------------------------------------------------------- 1 | 1 2 3 3 2 3 22 904 42 321 44 1 -32 -445 -23 23 4 50 0 0 1 2 8 3 1 2 9 3 4 -491 2 | -23 3 | 442 2045 4 | 696 7 707 5 | 6 | 7 | 409 6 89445 8 | 9 | 10 | 3 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ch10/10.34.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::vector vi{0, 1, 2, 3, 4, 5}; 6 | for (auto it = vi.crbegin(); it != vi.crend(); ++it) 7 | std::cout << *it << " "; 8 | std::cout << std::endl; 9 | 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /ch10/10.35.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::vector vi{0, 1, 2, 3, 4, 5}; 6 | for (auto it = --vi.end(); it + 1 != vi.begin(); --it) 7 | std::cout << *it << " "; 8 | std::cout << std::endl; 9 | 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /ch10/10.36.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::vector vi{0, 1, 2, 3, 4, 5, 0}; 6 | auto rit = find(vi.crbegin(), vi.crend(), 0); 7 | std::cout << "The last " << *rit << " in vector is at position " 8 | << rit.base() - vi.cbegin() - 1 << std::endl; 9 | //<< vi.crend() - rit - 1 << std::endl; 10 | // rit.base() is the iterator one past element 0, just like end iterator 11 | 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /ch10/10.37.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::vector vi{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 7 | std::list li(vi.rbegin() + 2, vi.rend() - 3); 8 | for (const auto &i : li) 9 | std::cout << i << " "; 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /ch10/10.39.md: -------------------------------------------------------------------------------- 1 | A `list` has bidirectional iterator. 2 | 3 | A `vector` has random-access iterator. 4 | -------------------------------------------------------------------------------- /ch10/10.4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::vector vi; 7 | for (double i; std::cin >> i; vi.push_back(i)) {} 8 | std::cout << "The sum of the sequence is " 9 | << std::accumulate(vi.cbegin(), vi.cend(), 0.0) << std::endl; 10 | //<< std::accumulate(vi.cbegin(), vi.cend(), 0) << std::endl; 11 | // The type of the third argument determines which + operator is used and is 12 | // the type that `accumulate` returns. The type of literal `0` is `int`, thus 13 | // we will lose all the decimals if we use `0`. 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /ch10/10.40.md: -------------------------------------------------------------------------------- 1 | `copy` requires input iterator as the first two parameters and output iterator as the third parameter. 2 | 3 | `reverse` requires bidirectional iterator. 4 | 5 | `unique` requires forward iterator. 6 | -------------------------------------------------------------------------------- /ch10/10.6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::vector vi(10, 1); 7 | std::list li(10, 1); 8 | std::fill_n(vi.begin(), vi.size(), 0); 9 | std::fill_n(li.begin(), li.size(), 0); 10 | std::cout << vi.back() << " " << li.back() << std::endl; 11 | 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /ch10/10.8.md: -------------------------------------------------------------------------------- 1 | Because all the changes of the container size are made by the insert iterator, not the algorithm. 2 | 3 | The algorithms may 4 | - read elements, 5 | - wirte elements (change the elements in the container), 6 | - reorder elements (change the sequence of the elements in the container), 7 | 8 | and the algorithms never 9 | - add/remove elements (change the size of the container). 10 | -------------------------------------------------------------------------------- /ch11/11.1.md: -------------------------------------------------------------------------------- 1 | A `map` is an associative container which contains an associative array of key-value pairs. Values are found by key. The key doesn't have to be integer. 2 | 3 | A `vector` is an sequential container which contains a normal array of values. Values are found by position. The position is integer. 4 | 5 | 6 | -------------------------------------------------------------------------------- /ch11/11.10.md: -------------------------------------------------------------------------------- 1 | We can define `map::iterator, int>` because the iterator of vector supports iterator arithmetic which includes `<` operator. 2 | But we cannot define `map::iterator, int>` because the iterator of list does not support iterator arithmetic and does not support `<` operator. 3 | -------------------------------------------------------------------------------- /ch11/11.11.md: -------------------------------------------------------------------------------- 1 | 2 | multiset 3 | 4 | -------------------------------------------------------------------------------- /ch11/11.12.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | std::vector> vp; 8 | std::string s; 9 | int i; 10 | while (std::cin >> s >> i) 11 | vp.push_back({s, i}); 12 | //vp.push_back(std::make_pair(s, i)); 13 | //vp.push_back(std::pair(s, i)); 14 | // I think the braced inititalizer is the most easy way. 15 | 16 | for (const auto &p : vp) 17 | std::cout << p.first << " : " << p.second << std::endl; 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /ch11/11.13.md: -------------------------------------------------------------------------------- 1 | See [ex11.12](11.12.cpp). 2 | -------------------------------------------------------------------------------- /ch11/11.15.md: -------------------------------------------------------------------------------- 1 | For `map>`: 2 | 3 | - `mapped_type` is `vector`. 4 | - `key_type` is `int`. 5 | - `value_type` is `pair>`. 6 | -------------------------------------------------------------------------------- /ch11/11.16.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::map mi; 6 | int a, b; 7 | while (std::cin >> a >> b) { 8 | auto it = mi.find(a); 9 | if (it != mi.end()) 10 | it->second = b; 11 | else 12 | mi.insert({a, b}); 13 | } 14 | for (auto it = mi.cbegin(); it != mi.cend(); ++it) 15 | std::cout << it->first << " : " << it->second << std::endl; 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /ch11/11.17.md: -------------------------------------------------------------------------------- 1 | Assume `multiset c; vector v;`, then 2 | 3 | copy(v.begin(), v.end(), inserter(c, c.end())); 4 | 5 | is OK. 6 | 7 | copy(v.begin(), v.end(), back_inserter(c)); 8 | 9 | is error. A `multiset` doesn't have `push_back` memeber function. 10 | 11 | copy(c.begin(), c.end(), inserter(v, v.end())); 12 | 13 | is OK. 14 | 15 | copy(c.begin(), c.end(), back_inserter(v)); 16 | 17 | is OK. 18 | -------------------------------------------------------------------------------- /ch11/11.18.md: -------------------------------------------------------------------------------- 1 | The type is 2 | 3 | map::const_iterator 4 | 5 | -------------------------------------------------------------------------------- /ch11/11.19.md: -------------------------------------------------------------------------------- 1 | The definition can be written as 2 | 3 | multiset::iterator it = bookstore.begin(); 4 | 5 | Note that iterators for `set`s are always `const`. 6 | -------------------------------------------------------------------------------- /ch11/11.2.md: -------------------------------------------------------------------------------- 1 | A `list` may be used when we need to insert/delete at the middle frequently, such as a linked list. 2 | 3 | A `vector` may be used when we need random-access, such as a dynamic normal array. 4 | 5 | A `deque` may be used like a queue. 6 | 7 | A `map` may be used like a dictionary. 8 | 9 | A `set` may be used to check whether a value is present. 10 | -------------------------------------------------------------------------------- /ch11/11.21.md: -------------------------------------------------------------------------------- 1 | while (cin >> word) 2 | ++word_count.insert({word, 0}).first->second; 3 | 4 | The code just does the same thing as `++word_count[word];`. If the `word` is in `map`, then increase the count of that word by 1, else insert that word into `map`, set the count to 0, and increase the count by 1. 5 | -------------------------------------------------------------------------------- /ch11/11.22.md: -------------------------------------------------------------------------------- 1 | The return type is `pair>::iterator, bool>`. 2 | -------------------------------------------------------------------------------- /ch11/11.24.md: -------------------------------------------------------------------------------- 1 | The code adds a new key `0` to the map `m` and value initializes its value to 0, then assigns 1 to its value. 2 | -------------------------------------------------------------------------------- /ch11/11.25.md: -------------------------------------------------------------------------------- 1 | The code will cause error. Because the subscript operator accesses element that not existed, the behaviour is undefined. 2 | -------------------------------------------------------------------------------- /ch11/11.26.md: -------------------------------------------------------------------------------- 1 | A type which can be used as a `key_type` can be used to subscript a `map`. The subscript operator return `mapped_type`. For example: 2 | 3 | map world_counts; 4 | string str("Hello"); 5 | int cnt = world_counts[str]; 6 | 7 | -------------------------------------------------------------------------------- /ch11/11.27.md: -------------------------------------------------------------------------------- 1 | We can use `count` if the key is present multiple times and we want to know how many. We can use `find` if we only want to know whether the key is present. 2 | -------------------------------------------------------------------------------- /ch11/11.28.md: -------------------------------------------------------------------------------- 1 | map> mp; 2 | map>::iterator it = mp.find("some key"); 3 | -------------------------------------------------------------------------------- /ch11/11.29.md: -------------------------------------------------------------------------------- 1 | When we pass a key that is not in container, 2 | 3 | - `upper_bound` will return `c.end()`, 4 | - `lower_bound` will return `c.end()`, 5 | - `equal_range` will return `make_pair(c.end(), c.end())`. 6 | -------------------------------------------------------------------------------- /ch11/11.30.md: -------------------------------------------------------------------------------- 1 | `pos` is a pair of iterators. 2 | 3 | `pos.first` is the first iterator in pair. 4 | 5 | `pos.first->second` derefences the iterator and get a pair of two strings, then returns the second string. 6 | -------------------------------------------------------------------------------- /ch11/11.32.md: -------------------------------------------------------------------------------- 1 | See [ex11.31](11.31.cpp). 2 | -------------------------------------------------------------------------------- /ch11/11.33.dict.in: -------------------------------------------------------------------------------- 1 | brb be right back 2 | k okay? 3 | y why 4 | r are 5 | u you 6 | pic picture 7 | thk thanks! 8 | l8r later 9 | cy see you 10 | fuck f**k 11 | shit s**t 12 | bitch b***h 13 | -------------------------------------------------------------------------------- /ch11/11.33.text.in: -------------------------------------------------------------------------------- 1 | where r u 2 | y dont u send me a pic 3 | k thk cy l8r 4 | -------------------------------------------------------------------------------- /ch11/11.34.md: -------------------------------------------------------------------------------- 1 | When we use subscript operator instead of `find`, if a word is not in the map, it will be inserted into the map, and then transform into empty string, which is the value initialized value. 2 | -------------------------------------------------------------------------------- /ch11/11.35.md: -------------------------------------------------------------------------------- 1 | The original form of code will replace the old phrase with the new phrase which has the same abbrivation. 2 | 3 | The new form of code will keep the old phrase and ignore the new phrase which has the same abbrivation. 4 | -------------------------------------------------------------------------------- /ch11/11.36.dict.in: -------------------------------------------------------------------------------- 1 | brb be right back 2 | err1 3 | err2 4 | k okay? 5 | y why 6 | r are 7 | u you 8 | pic picture 9 | thk thanks! 10 | l8r later 11 | cy see you 12 | fuck f**k 13 | shit s**t 14 | bitch b***h 15 | -------------------------------------------------------------------------------- /ch11/11.36.md: -------------------------------------------------------------------------------- 1 | Use program in [ex11.33](11.33.cpp) and input file [11.36.dict.in](11.36.dict.in) as an example, in which `err1` is a line that has a key, one space, and end of the line, `err2` is a line that has a key, two spaces, and end of the line. `err1` will cause an error, while `err2` will be transformed into empty string. 2 | -------------------------------------------------------------------------------- /ch11/11.37.md: -------------------------------------------------------------------------------- 1 | The advantages of an unordered container are 2 | - using hashing, which gives better average case performance in principle, 3 | - having no cost of maintaining elements in order, 4 | - finding elements at const time. 5 | 6 | The advantages of an ordered container are 7 | - all keys being sorted alphabetically, 8 | - easier to use (no need to find a effective hashing). 9 | -------------------------------------------------------------------------------- /ch11/11.4.in: -------------------------------------------------------------------------------- 1 | abc ab a a, a,,, ,,,a ,a ,, ,,,,? ?? 2 | "abc" `AbC``` 3 | 'ab' `aa` 4 | "example." "example," and "Example" 5 | 6 | ['x', 'y'] ['p','q'] 7 | {"Hello, world"; "Two"; "THREE"} 8 | - Fourth 9 | - Fifth 10 | some-word other-word -aword a-very-long-word 11 | -------------------------------------------------------------------------------- /ch11/11.5.md: -------------------------------------------------------------------------------- 1 | A `map` is a collection of key-value pairs. When we want a container acting like dictionary, we should choose `map`. 2 | 3 | A `set` is a collection of keys. When we want to check if some values are present, we can choose `set`. 4 | -------------------------------------------------------------------------------- /ch11/11.6.md: -------------------------------------------------------------------------------- 1 | A `set` is an associative container while a `list` is a sequential container. Elements in `list` can be sorted by user while elements in `set` is sorted automatically (except unordered version). A `list` can be ordered while a `set` is un-ordered. We can't enforce an arbitrary order by placing an arbitrary element in an arbitrary position in a `set`. 2 | -------------------------------------------------------------------------------- /ch11/11.9.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | std::map> words{ 8 | {"ghi", {100, 200}}, {"abc", {1, 3, 5}}, {"def", {2, 4}}}; 9 | 10 | for (const auto &w : words) { 11 | std::cout << w.first << ":"; 12 | for (const auto &l : w.second) 13 | std::cout << " " << l; 14 | std::cout << std::endl; 15 | } 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /ch12/12.1.md: -------------------------------------------------------------------------------- 1 | At the end of code, `b2` is destoryed, `b1` has 4 elements. 2 | -------------------------------------------------------------------------------- /ch12/12.10.md: -------------------------------------------------------------------------------- 1 | The call is correct. In the function `process`, the parameter `ptr` is a copy of the original shared pointer `p`, which increases the reference count. Before the function scope ends, `ptr` is destoryed and the reference count decreased back to the original value. Thus, after the function `process` is executed, the reference count does not change. 2 | -------------------------------------------------------------------------------- /ch12/12.11.md: -------------------------------------------------------------------------------- 1 | The call is error. Unlike [ex12.10](12.10.md), using `p.get()` to initialize the parameter `ptr` of function `process` creates a new `shared_ptr` which is independent of the original `shared_ptr`, but sharing the same underlying memory. Those two pointers have no awareness of each other even though they point to the same memory. Thus, before the end of function scope, the newly created `ptr` is destoryed, and according to its reference count, it is the only `shared_ptr` pointing the memory, the memoried is freed. However, the pointer `p` in the caller function still points to that memory. So the call is error. 2 | -------------------------------------------------------------------------------- /ch12/12.13.md: -------------------------------------------------------------------------------- 1 | The code is error. The memory pointed by smart pointer `sp` is freed by `delete p;`, and `sp` becomes a dangling pointer. It will cause some problems. We cannot dereference any one of the shared pointers which point to the same memory that `sp` pointed, and when all these shared pointers are destoryed, the memory will be freed again. 2 | -------------------------------------------------------------------------------- /ch12/12.16.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | std::unique_ptr p(new int(5)); 5 | 6 | //std::unique_ptr q(p); 7 | 8 | std::unique_ptr q; 9 | //q = p; 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /ch12/12.18.md: -------------------------------------------------------------------------------- 1 | Because we can have as much `shared_ptr`s as we want point to the same memory. Thus the ownership of the memory do not need to be released by one pointer and pass to another pointer. 2 | -------------------------------------------------------------------------------- /ch12/12.19/StrBlobPtr.h: -------------------------------------------------------------------------------- 1 | #ifndef STRBLOBPTR_H 2 | #define STRBLOBPTR_H 3 | 4 | class StrBlob; 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | class StrBlobPtr { 11 | public: 12 | typedef std::vector::size_type size_type; 13 | 14 | StrBlobPtr(); 15 | explicit StrBlobPtr(StrBlob &sb, size_type pos = 0); 16 | 17 | std::string &deref() const; 18 | StrBlobPtr &inc(); 19 | 20 | private: 21 | std::weak_ptr> wptr; 22 | size_type curr; 23 | 24 | std::shared_ptr> 25 | check(size_type pos, const std::string &msg) const; 26 | }; 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /ch12/12.20/StrBlobPtr.h: -------------------------------------------------------------------------------- 1 | #ifndef STRBLOBPTR_H 2 | #define STRBLOBPTR_H 3 | 4 | class StrBlob; 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | class StrBlobPtr { 11 | public: 12 | typedef std::vector::size_type size_type; 13 | 14 | StrBlobPtr(); 15 | explicit StrBlobPtr(StrBlob &sb, size_type pos = 0); 16 | 17 | std::string &deref() const; 18 | StrBlobPtr &inc(); 19 | 20 | private: 21 | std::weak_ptr> wptr; 22 | size_type curr; 23 | 24 | std::shared_ptr> 25 | check(size_type pos, const std::string &msg) const; 26 | }; 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /ch12/12.21.md: -------------------------------------------------------------------------------- 1 | I think it depends on personal preference. Both versions work correctly. The original verison is easy to understand while using a temperoary variable, the new version is succinct while hard to understand. 2 | -------------------------------------------------------------------------------- /ch12/12.22/StrBlobPtr.h: -------------------------------------------------------------------------------- 1 | #ifndef STRBLOBPTR_H 2 | #define STRBLOBPTR_H 3 | 4 | class StrBlob; 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | class StrBlobPtr { 11 | public: 12 | typedef std::vector::size_type size_type; 13 | 14 | StrBlobPtr(); 15 | explicit StrBlobPtr(StrBlob &sb, size_type pos = 0); 16 | 17 | std::string &deref() const; 18 | StrBlobPtr &inc(); 19 | 20 | private: 21 | std::weak_ptr> wptr; 22 | size_type curr; 23 | 24 | std::shared_ptr> 25 | check(size_type pos, const std::string &msg) const; 26 | }; 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /ch12/12.23.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | const char *c1 = "Hello "; 6 | const char *c2 = "World"; 7 | char *c3 = new char[std::strlen(c1) + std::strlen(c2) + 1]; 8 | std::strcpy(c3, c1); 9 | std::strcat(c3, c2); 10 | std::cout << c3 << std::endl; 11 | delete [] c3; 12 | 13 | std::string s1("Hello "); 14 | std::string s2("World"); 15 | std::string s3 = s1 + s2; 16 | std::cout << s3 << std::endl; 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /ch12/12.24.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | std::cout << "Input string length: "; 5 | size_t len; 6 | std::cin >> len; 7 | std::cin.ignore(); // ignore one char after the length number 8 | char *ca = new char[len + 1]; 9 | std::cin.get(ca, len + 1); 10 | std::cout << "The input string is:\n\"" << ca << "\"" << std::endl; 11 | 12 | // If the input string is longer than the size of the array, then all input 13 | // characters whose positions are after the array size will be ignored. 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /ch12/12.25.md: -------------------------------------------------------------------------------- 1 | delete [] pa; 2 | -------------------------------------------------------------------------------- /ch12/12.27/12.27.in: -------------------------------------------------------------------------------- 1 | This is a test for same words occurs on the same line. 2 | 3 | And different line. 4 | 5 | -------------------------------------------------------------------------------- /ch12/12.27/QueryResult.cpp: -------------------------------------------------------------------------------- 1 | #include "QueryResult.h" 2 | 3 | std::string make_plural(int cnt, const std::string &s, 4 | const std::string &postfix = "s") { 5 | return cnt > 1 ? s + postfix : s; 6 | } 7 | 8 | std::ostream &print(std::ostream &os, const QueryResult &qr) { 9 | std::cout << "\"" << qr.word << "\" occurs " << qr.total << " " 10 | << make_plural(qr.total, "time") << ":\n"; 11 | if (qr.total > 0) 12 | for (const auto &ln : *qr.line_numbers) { 13 | std::cout << "(line " << ln + 1 << ") " 14 | << (*qr.line_text)[ln] << std::endl; 15 | } 16 | return os; 17 | } 18 | -------------------------------------------------------------------------------- /ch12/12.27/TextQuery.h: -------------------------------------------------------------------------------- 1 | #ifndef TEXTQUERY_H 2 | #define TEXTQUERY_H 3 | 4 | class QueryResult; 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | class TextQuery { 14 | public: 15 | typedef std::vector::size_type line_no_type; 16 | 17 | explicit TextQuery(std::ifstream &in); 18 | 19 | QueryResult query(const std::string &word) const; 20 | 21 | private: 22 | std::shared_ptr> text; 23 | std::map>> lines; 24 | }; 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /ch12/12.3.md: -------------------------------------------------------------------------------- 1 | No, a `const` object of this class type should not be able to change the object. Thus we should not define `const` version of `push_back` or `pop_back`. Although the complier does not report errors if we define `const` versions of `push_back` and `pop_back`, it is not logical for a `const` object. 2 | -------------------------------------------------------------------------------- /ch12/12.30/12.30.in: -------------------------------------------------------------------------------- 1 | This is a test for same words occurs on the same line. 2 | 3 | And different line. 4 | 5 | -------------------------------------------------------------------------------- /ch12/12.30/QueryResult.cpp: -------------------------------------------------------------------------------- 1 | #include "QueryResult.h" 2 | 3 | std::string make_plural(int cnt, const std::string &s, 4 | const std::string &postfix = "s") { 5 | return cnt > 1 ? s + postfix : s; 6 | } 7 | 8 | std::ostream &print(std::ostream &os, const QueryResult &qr) { 9 | std::cout << "\"" << qr.word << "\" occurs " << qr.total << " " 10 | << make_plural(qr.total, "time") << ":\n"; 11 | //if (qr.total > 0) 12 | for (const auto &ln : *qr.line_numbers) { 13 | std::cout << "(line " << ln + 1 << ") " 14 | << (*qr.line_text)[ln] << std::endl; 15 | } 16 | return os; 17 | } 18 | -------------------------------------------------------------------------------- /ch12/12.30/TextQuery.h: -------------------------------------------------------------------------------- 1 | #ifndef TEXTQUERY_H 2 | #define TEXTQUERY_H 3 | 4 | class QueryResult; 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | class TextQuery { 14 | public: 15 | typedef std::vector::size_type line_no_type; 16 | 17 | explicit TextQuery(std::ifstream &in); 18 | 19 | QueryResult query(const std::string &word) const; 20 | 21 | private: 22 | std::shared_ptr> text; 23 | std::map>> word_map; 24 | }; 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /ch12/12.31.md: -------------------------------------------------------------------------------- 1 | Then the order of the line numbers in the container is the same with the push order (although no influence in this case), and we must handle duplicates by ourselves. 2 | 3 | I think `set` is better for our purpose, since we don't need duplicated line numbers. The only information we want to know is which line cotains the word, not how many times the word occurs on the same line. 4 | -------------------------------------------------------------------------------- /ch12/12.32/12.32.in: -------------------------------------------------------------------------------- 1 | This is a test for same words occurs on the same line. 2 | 3 | And different line. 4 | 5 | -------------------------------------------------------------------------------- /ch12/12.32/QueryResult.cpp: -------------------------------------------------------------------------------- 1 | #include "QueryResult.h" 2 | #include "StrBlobPtr.h" 3 | 4 | std::string make_plural(int cnt, const std::string &s, 5 | const std::string &postfix = "s") { 6 | return cnt > 1 ? s + postfix : s; 7 | } 8 | 9 | std::ostream &print(std::ostream &os, const QueryResult &qr) { 10 | std::cout << "\"" << qr.word << "\" occurs " << qr.total << " " 11 | << make_plural(qr.total, "time") << ":\n"; 12 | for (const auto &ln : *qr.line_numbers) 13 | std::cout << "(line " << ln + 1 << ") " 14 | << StrBlobPtr(*qr.line_text, ln).deref() << std::endl; 15 | return os; 16 | } 17 | -------------------------------------------------------------------------------- /ch12/12.32/StrBlobPtr.h: -------------------------------------------------------------------------------- 1 | #ifndef STRBLOBPTR_H 2 | #define STRBLOBPTR_H 3 | 4 | class StrBlob; 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | class StrBlobPtr { 11 | public: 12 | typedef std::vector::size_type size_type; 13 | 14 | StrBlobPtr(); 15 | explicit StrBlobPtr(StrBlob &sb, size_type pos = 0); 16 | 17 | std::string &deref() const; 18 | StrBlobPtr &inc(); 19 | 20 | private: 21 | std::weak_ptr> wptr; 22 | size_type curr; 23 | 24 | std::shared_ptr> 25 | check(size_type pos, const std::string &msg) const; 26 | }; 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /ch12/12.32/TextQuery.h: -------------------------------------------------------------------------------- 1 | #ifndef TEXTQUERY_H 2 | #define TEXTQUERY_H 3 | 4 | class QueryResult; 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "StrBlob.h" 13 | 14 | class TextQuery { 15 | public: 16 | typedef StrBlob::size_type line_no_type; 17 | 18 | explicit TextQuery(std::ifstream &in); 19 | 20 | QueryResult query(const std::string &word) const; 21 | 22 | private: 23 | std::shared_ptr text; 24 | std::map>> word_map; 25 | }; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /ch12/12.33/12.33.in: -------------------------------------------------------------------------------- 1 | This is a test for same words occurs on the same line. 2 | 3 | And different line. 4 | 5 | -------------------------------------------------------------------------------- /ch12/12.33/QueryResult.cpp: -------------------------------------------------------------------------------- 1 | #include "QueryResult.h" 2 | #include "StrBlobPtr.h" 3 | 4 | std::string make_plural(int cnt, const std::string &s, 5 | const std::string &postfix = "s") { 6 | return cnt > 1 ? s + postfix : s; 7 | } 8 | 9 | std::ostream &print(std::ostream &os, const QueryResult &qr) { 10 | std::cout << "\"" << qr.word << "\" occurs " << qr.total << " " 11 | << make_plural(qr.total, "time") << ":\n"; 12 | for (const auto &ln : *qr.line_numbers) 13 | std::cout << "(line " << ln + 1 << ") " 14 | << StrBlobPtr(*qr.line_text, ln).deref() << std::endl; 15 | return os; 16 | } 17 | -------------------------------------------------------------------------------- /ch12/12.33/StrBlobPtr.h: -------------------------------------------------------------------------------- 1 | #ifndef STRBLOBPTR_H 2 | #define STRBLOBPTR_H 3 | 4 | class StrBlob; 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | class StrBlobPtr { 11 | public: 12 | typedef std::vector::size_type size_type; 13 | 14 | StrBlobPtr(); 15 | explicit StrBlobPtr(StrBlob &sb, size_type pos = 0); 16 | 17 | std::string &deref() const; 18 | StrBlobPtr &inc(); 19 | 20 | private: 21 | std::weak_ptr> wptr; 22 | size_type curr; 23 | 24 | std::shared_ptr> 25 | check(size_type pos, const std::string &msg) const; 26 | }; 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /ch12/12.33/TextQuery.h: -------------------------------------------------------------------------------- 1 | #ifndef TEXTQUERY_H 2 | #define TEXTQUERY_H 3 | 4 | class QueryResult; 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "StrBlob.h" 13 | 14 | class TextQuery { 15 | public: 16 | typedef StrBlob::size_type line_no_type; 17 | 18 | explicit TextQuery(std::ifstream &in); 19 | 20 | QueryResult query(const std::string &word) const; 21 | 22 | private: 23 | std::shared_ptr text; 24 | std::map>> word_map; 25 | }; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /ch12/12.4.md: -------------------------------------------------------------------------------- 1 | Because `i` is an `unsigned` type, which means `i` will always be nonnegative. 2 | -------------------------------------------------------------------------------- /ch12/12.5.md: -------------------------------------------------------------------------------- 1 | Since we do not make the constructor `explicit`, the pros are 2 | - we can use `= { /* ... */ }` to initialize a `StrBlob` object, 3 | - we can use assignment to assign an initializer list to a `StrBlob` object, 4 | - we can pass an initializer list to functions who need a `StrBlob` parameter. 5 | 6 | The cons are 7 | - we may overlook the implicit conversion made by compiler sometime, which may be bug prone. 8 | -------------------------------------------------------------------------------- /ch12/12.6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | std::vector *factory_veci() { 5 | return new std::vector; 6 | } 7 | 8 | void set_veci(std::vector *vip) { 9 | for (int i; std::cin >> i; vip->push_back(i)) {} 10 | } 11 | 12 | void print_veci(std::vector *vip) { 13 | for (const auto &i : *vip) 14 | std::cout << i << " "; 15 | std::cout << std::endl; 16 | } 17 | 18 | int main() { 19 | auto *p = factory_veci(); 20 | set_veci(p); 21 | print_veci(p); 22 | delete p; 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /ch12/12.7.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef std::shared_ptr> share_vec_ptr; 6 | 7 | share_vec_ptr factory_veci() { 8 | return std::make_shared>(); 9 | } 10 | 11 | void set_veci(share_vec_ptr vip) { 12 | for (int i; std::cin >> i; vip->push_back(i)) {} 13 | } 14 | 15 | void print_veci(share_vec_ptr vip) { 16 | for (const auto &i : *vip) 17 | std::cout << i << " "; 18 | std::cout << std::endl; 19 | } 20 | 21 | int main() { 22 | auto p = factory_veci(); 23 | set_veci(p); 24 | print_veci(p); 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /ch12/12.8.md: -------------------------------------------------------------------------------- 1 | The return type should be a `int *`, otherwise the memory of the `int` pointed by `p` is leaked. 2 | -------------------------------------------------------------------------------- /ch12/12.9.md: -------------------------------------------------------------------------------- 1 | int *q = new int(42), *r = new int(100); 2 | r = q; 3 | 4 | `r` and `q` points to the same memory, while the old memory pointed by `r` is leaked, since no pointer points to it and it is not freed. 5 | 6 | auto q2 = make_shared(42), r2 = make_shared(100); 7 | r2 = q2; 8 | 9 | First, the reference count of `r2` is decreased, and the memory pointed by `r2` is freed, since no `shared_ptr` points to it. Second, `r2` and `q2` point to the same memory, and the reference count of both smart pointers are increased. 10 | -------------------------------------------------------------------------------- /ch13/13.1.md: -------------------------------------------------------------------------------- 1 | A copy constructor is a constructor whose first parameter is a reference to the class type and any additional parameters have default values. 2 | 3 | The copy constructor may be used when we use copy initialization, but not always. 4 | -------------------------------------------------------------------------------- /ch13/13.10.md: -------------------------------------------------------------------------------- 1 | When a `StrBlob` object is destroyed, the shared pointer member is destroyed by calling the pointer's destructor, thus decreasing the reference count of the shared pointer, if the count is zero, then the vector pointed by the smart pointer is destroyed too. 2 | 3 | When a `StrBlobPtr` object is destroyed, the weak pointer member is destroyed by calling the pointer's destructor, the vector pointed by the smart pointer is not affected. 4 | -------------------------------------------------------------------------------- /ch13/13.12.md: -------------------------------------------------------------------------------- 1 | bool fcn(const Sales_data *trans, Sales_data accum) 2 | { 3 | Sales_data item1(*trans), item2(accum); 4 | return item1.isbn() != item2.isbn(); 5 | } 6 | 7 | 3 destructors are called on `accum`, `item1` and `item2`. 8 | -------------------------------------------------------------------------------- /ch13/13.14.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using std::cout; using std::endl; 3 | 4 | class numbered { 5 | public: 6 | numbered() : mysn(++sn) {} 7 | int mysn; 8 | private: 9 | static int sn; 10 | }; 11 | 12 | int numbered::sn = 0; 13 | 14 | void f(numbered s) { 15 | cout << s.mysn << endl; 16 | } 17 | 18 | int main() { 19 | numbered a, b = a, c = b; 20 | f(a); // 1 21 | f(b); // 1 22 | f(c); // 1 23 | numbered d; 24 | f(d); // 2 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /ch13/13.15.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using std::cout; using std::endl; 3 | 4 | class numbered { 5 | public: 6 | numbered() : mysn(++sn) {} 7 | numbered(const numbered &) : mysn(++sn) {} 8 | int mysn; 9 | private: 10 | static int sn; 11 | }; 12 | 13 | int numbered::sn = 0; 14 | 15 | void f(numbered s) { 16 | // `s` is copy initialized from argument, thus `s.mysn` is not the same with 17 | // the argument we passed in. 18 | cout << s.mysn << endl; 19 | } 20 | 21 | int main() { 22 | numbered a, b = a, c = b; // a.mysn = 1, b.mysn = 2, c.mysn = 3 23 | f(a); // 4 24 | f(b); // 5 25 | f(c); // 6 26 | numbered d; 27 | f(d); // 8 28 | 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /ch13/13.16.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using std::cout; using std::endl; 3 | 4 | class numbered { 5 | public: 6 | numbered() : mysn(++sn) {} 7 | numbered(const numbered &) : mysn(++sn) {} 8 | int mysn; 9 | private: 10 | static int sn; 11 | }; 12 | 13 | int numbered::sn = 0; 14 | 15 | void f(const numbered &s) { // the reference will not use copy initialization 16 | cout << s.mysn << endl; 17 | } 18 | 19 | int main() { 20 | numbered a, b = a, c = b; // a.mysn = 1, b.mysn = 2, c.mysn = 3 21 | f(a); // 1 22 | f(b); // 2 23 | f(c); // 3 24 | numbered d; 25 | f(d); // 4 26 | 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /ch13/13.17.md: -------------------------------------------------------------------------------- 1 | See [ex13.14](ex13.14.cpp), [ex13.15](ex13.15.cpp) and [ex13.16](ex13.16.cpp). 2 | -------------------------------------------------------------------------------- /ch13/13.2.md: -------------------------------------------------------------------------------- 1 | The parameter of the constructor should be a reference, otherwise the call would never succeed. To call the copy constructor, we'd need to use the copy constructor to copy the argument, but to copy the argument, we'd need to call the copy constructor, and so on indefinitely. 2 | -------------------------------------------------------------------------------- /ch13/13.21.md: -------------------------------------------------------------------------------- 1 | No, they don't need. Becasue all the members of class `TextQuery` and `QueryResult` are copyed or destroyed correctly by the synthesized copy-control members. 2 | -------------------------------------------------------------------------------- /ch13/13.22.md: -------------------------------------------------------------------------------- 1 | See [ex13.11](13.11.cpp). 2 | -------------------------------------------------------------------------------- /ch13/13.24.md: -------------------------------------------------------------------------------- 1 | If we didn't define a destructor, the memory stored the string will be leak. 2 | 3 | If we didn't define a copy constructor, then both the new object and the old object being copyed will point to the same underline string. 4 | -------------------------------------------------------------------------------- /ch13/13.25.md: -------------------------------------------------------------------------------- 1 | The copy constructor and the copy-assignment operator need to copy the underlying vector to a new vector rather than copy the shared pointer. 2 | 3 | The pointer we use is smart pointer, and the memory of the vector is handled by the smart pointer, so that we don't need use destructor to release the memory by ourself. 4 | -------------------------------------------------------------------------------- /ch13/13.26/StrBlobPtr.h: -------------------------------------------------------------------------------- 1 | #ifndef STRBLOBPTR_H 2 | #define STRBLOBPTR_H 3 | 4 | class StrBlob; 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | class StrBlobPtr { 11 | public: 12 | typedef std::vector::size_type size_type; 13 | 14 | StrBlobPtr(); 15 | explicit StrBlobPtr(StrBlob &sb, size_type pos = 0); 16 | 17 | std::string &deref() const; 18 | StrBlobPtr &inc(); 19 | 20 | private: 21 | std::weak_ptr> wptr; 22 | size_type curr; 23 | 24 | std::shared_ptr> 25 | check(size_type pos, const std::string &msg) const; 26 | }; 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /ch13/13.29.md: -------------------------------------------------------------------------------- 1 | Beacuse the two `swap` functions called inside `swap(HasPtr &lhs, HasPtr &rhs)` are the overloaded versions of `swap` function in standard library. 2 | -------------------------------------------------------------------------------- /ch13/13.3.md: -------------------------------------------------------------------------------- 1 | When we copy a `StrBlob`, the underlying smart pointer is copyed. But the vector to which the pointer pointed is not copyed, which means both `StrBlob` objects will use the same vector. This may not be what we want. 2 | 3 | When we copy a `StrBlobPtr`, the same thing happens as copying a `StrBlob`, but this may be what we want. 4 | -------------------------------------------------------------------------------- /ch13/13.32.md: -------------------------------------------------------------------------------- 1 | No, because all the data members of pointerlike version of `HasPtr` are built-in types (integral, pointer) and they are swapped efficiently using library `swap`. 2 | -------------------------------------------------------------------------------- /ch13/13.33.md: -------------------------------------------------------------------------------- 1 | Because we want use the parameter to change the value of the argument. 2 | -------------------------------------------------------------------------------- /ch13/13.38.md: -------------------------------------------------------------------------------- 1 | If we use copy and swap to define the `Message` copy-assignment operator, we will 2 | 3 | 1. add the copyed message to folders containing the original message, 4 | 2. remove both the copyed message and the `lhs` message from their folders, 5 | 3. swap the value of the `lhs` and the copyed message, 6 | 4. add the swapped `lhs` and the copy-swapped message to their folders, 7 | 5. remove the copy-swapped message from its folders. 8 | 9 | This means we call copy-constructor one time, `swap` one time and destructor one time, and it is much more work than the current version. 10 | -------------------------------------------------------------------------------- /ch13/13.4.md: -------------------------------------------------------------------------------- 1 | Point global; 2 | Point foo_bar(Point arg) // copy initialize `arg` may use copy constructor 3 | { 4 | Point local = arg, *heap = new Point(global); 5 | // copy initialize `local` may use copy constructor 6 | // copy initialize `heap` may use copy constructor 7 | *heap = local; 8 | Point pa[ 4 ] = { local, *heap }; 9 | // brace initialize the elements in array `pa` will use copy 10 | // initialization, which may use copy constructor 11 | return *heap; 12 | // copy initialize the return object may use copy constructor 13 | } 14 | -------------------------------------------------------------------------------- /ch13/13.41.md: -------------------------------------------------------------------------------- 1 | Because the pointer range is `[bg, ed)`. The memory pointed by `first_free` is where we want to construct new string, and after we constructed the new string, the pointer is increased to point to the next place in memory. 2 | -------------------------------------------------------------------------------- /ch13/13.42/13.42.in: -------------------------------------------------------------------------------- 1 | This is a test for same words occurs on the same line. 2 | 3 | And different line. 4 | 5 | -------------------------------------------------------------------------------- /ch13/13.42/QueryResult.cpp: -------------------------------------------------------------------------------- 1 | #include "QueryResult.h" 2 | 3 | std::string make_plural(int cnt, const std::string &s, 4 | const std::string &postfix = "s") { 5 | return cnt > 1 ? s + postfix : s; 6 | } 7 | 8 | std::ostream &print(std::ostream &os, const QueryResult &qr) { 9 | std::cout << "\"" << qr.word << "\" occurs " << qr.total << " " 10 | << make_plural(qr.total, "time") << ":\n"; 11 | for (const auto &ln : *qr.line_numbers) 12 | std::cout << "(line " << ln + 1 << ") " 13 | << *(qr.line_text->begin() + ln) << std::endl; 14 | return os; 15 | } 16 | -------------------------------------------------------------------------------- /ch13/13.42/TextQuery.h: -------------------------------------------------------------------------------- 1 | #ifndef TEXTQUERY_H 2 | #define TEXTQUERY_H 3 | 4 | class QueryResult; 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "StrVec.h" 13 | 14 | class TextQuery { 15 | public: 16 | typedef StrVec::size_type line_no_type; 17 | 18 | explicit TextQuery(std::ifstream &in); 19 | 20 | QueryResult query(const std::string &word) const; 21 | 22 | private: 23 | std::shared_ptr text; 24 | std::map>> word_map; 25 | }; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /ch13/13.45.md: -------------------------------------------------------------------------------- 1 | An **rvalue reference** is a reference that must be bounded to an rvalue. It refers to an object's **value**. Rvalues are ephemeral. 2 | 3 | An **lvalue reference** (regular reference) is a reference that must be bounded to an lvalue or `const` rvalue. It refers to an object's **identity**. Lvalues are pesistent. 4 | -------------------------------------------------------------------------------- /ch13/13.46.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int f() { return 0; } 4 | 5 | int main() { 6 | std::vector vi(100); 7 | 8 | int &&r1 = f(); // function that returns a nonreference type 9 | int &r2 = vi[0]; // subscript operator 10 | int &r3 = r1; // variable 11 | int &&r4 = vi[0] * f(); // arithemtic operator 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /ch13/13.48.md: -------------------------------------------------------------------------------- 1 | See [ex13.47](13.47). 2 | -------------------------------------------------------------------------------- /ch13/13.5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class HasPtr { 5 | public: 6 | HasPtr(const std::string &s = std::string()) 7 | : ps(new std::string(s)), i(0) {} 8 | HasPtr(const HasPtr &ori) 9 | : ps(new std::string(*ori.ps)), i(ori.i) {} 10 | 11 | const std::string &get() const { return *ps; } 12 | void set(const std::string &s) { *ps = s; } 13 | 14 | private: 15 | std::string *ps; 16 | int i; 17 | }; 18 | 19 | int main() { 20 | HasPtr hp1 = "World"; 21 | HasPtr hp2 = hp1; 22 | hp1.set("Hello"); 23 | 24 | std::cout << hp1.get() << " " << hp2.get() << std::endl; 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /ch13/13.50.md: -------------------------------------------------------------------------------- 1 | See [ex13.49](13.49). 2 | -------------------------------------------------------------------------------- /ch13/13.51.md: -------------------------------------------------------------------------------- 1 | Because the function `clone` return a rvalue. The compiler knows that the object being returned is about to be destroyed. So that when we construct a new object from the return value or assign the return value to an object, we call move constructor or move-assignment operator. Thus no copy is made. The resource is moved from the return object to the new object. 2 | -------------------------------------------------------------------------------- /ch13/13.52.md: -------------------------------------------------------------------------------- 1 | When the assignment `hp = hp2;` is executed, the copy-assignment operator is used. First, data members of `rhs` (i.e. `hp2`) are copyed. Then, data members of `rhs` (i.e. `hp`) are deleted. Finally, the copyed data members of `rhs` are assigned to those of `lhs`. 2 | 3 | When the assignment `hp = std::move(hp2);` is executed, the move-assignment operator is used. First, `std::move()` return the rvalue reference to `hp2`. Second, the data members of the `rhs` (i.e. rvalue reference to `hp2`) are moved to those of `lhs` (i.e. `hp1`). Finally, the data members of `rhs` are assigned to valid values for destruction. 4 | -------------------------------------------------------------------------------- /ch13/13.55/StrBlobPtr.h: -------------------------------------------------------------------------------- 1 | #ifndef STRBLOBPTR_H 2 | #define STRBLOBPTR_H 3 | 4 | class StrBlob; 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | class StrBlobPtr { 11 | public: 12 | typedef std::vector::size_type size_type; 13 | 14 | StrBlobPtr(); 15 | explicit StrBlobPtr(StrBlob &sb, size_type pos = 0); 16 | 17 | std::string &deref() const; 18 | StrBlobPtr &inc(); 19 | 20 | private: 21 | std::weak_ptr> wptr; 22 | size_type curr; 23 | 24 | std::shared_ptr> 25 | check(size_type pos, const std::string &msg) const; 26 | }; 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /ch13/13.57.md: -------------------------------------------------------------------------------- 1 | See [ex13.56](13.56.cpp). 2 | -------------------------------------------------------------------------------- /ch13/13.58.md: -------------------------------------------------------------------------------- 1 | See [ex13.56](13.56.cpp). 2 | -------------------------------------------------------------------------------- /ch13/13.7.md: -------------------------------------------------------------------------------- 1 | When we assign one `StrBlob` to another, the underlying smart pointer is copyed. But the vector to which the pointer pointed is not copyed, which means both `StrBlob` objects will use the same vector. This may not be what we want. 2 | 3 | When we assign one `StrBlobPtr` to another, the same thing happens as assigning a `StrBlob`, but this may be what we want. 4 | -------------------------------------------------------------------------------- /ch13/13.9.md: -------------------------------------------------------------------------------- 1 | > What is a destructor? 2 | 3 | A destructor is a member function with the name of the class prefixed by a tilde (~) and has no return value and takes no parameters. 4 | 5 | > What does the synthesized destructor do? 6 | 7 | The synthesized destructor disallows objects of the type from being destroyed for some classes. Otherwise, it has an empty function body and the members are automatically destoryed after the empty destructor body is run. 8 | 9 | > When is a destructor synthesized? 10 | 11 | The compiler defines a synthesized destructor for any class that does not define its own destructor. 12 | -------------------------------------------------------------------------------- /ch14/14.10.md: -------------------------------------------------------------------------------- 1 | (a) The data will be properly read. 2 | 3 | (b) The data cannot be properly read, but the state of `istream` is still correct. After reading `10` as `bookNo`, an unsigned number is wanted, thus `24` will be read into `units_sold`, then a double is wanted, thus `0.95` will be read into `revenue`. 4 | -------------------------------------------------------------------------------- /ch14/14.11.md: -------------------------------------------------------------------------------- 1 | This input operator does not maintain the proper state of the destination object if errors occur during input. 2 | 3 | If we gave this operator the data in previous exercise, the first group would be read correctly, while the second wouldn't and the state of the object would be inconsistent. 4 | -------------------------------------------------------------------------------- /ch14/14.20.md: -------------------------------------------------------------------------------- 1 | See [ex14.13](14.13.cpp). 2 | -------------------------------------------------------------------------------- /ch14/14.29.md: -------------------------------------------------------------------------------- 1 | The increment/decrement operator will change the object, thus they cannot be used by a `const` object. 2 | -------------------------------------------------------------------------------- /ch14/14.3.md: -------------------------------------------------------------------------------- 1 | (a) `"cobble" == "stone"` built-in `operator==` 2 | 3 | (b) `svec1[0] == svec2[0]` overloaded `operator==` in `string` 4 | 5 | (c) `svec1 == svec2` overloaded `operator==` in `vector` 6 | 7 | (d) `"svec1[0] == "stone"` overloaded `operator==` in `string` 8 | -------------------------------------------------------------------------------- /ch14/14.31.md: -------------------------------------------------------------------------------- 1 | Because all data members of `StrBlobPtr` class can be copyed, assigned or destroyed properly by the synthesized copy-control members. 2 | -------------------------------------------------------------------------------- /ch14/14.33.md: -------------------------------------------------------------------------------- 1 | An overloaded function-call operator can take any number of operands as long as the overloaded function-call operator differ from all other overloads as to the number or types of their parameters. 2 | -------------------------------------------------------------------------------- /ch14/14.34.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class IfThenElse { 4 | public: 5 | typedef int value_type; 6 | value_type operator()(bool condition, value_type t, value_type f) const { 7 | return condition ? t : f; 8 | } 9 | }; 10 | 11 | int main() { 12 | int n; 13 | std::cin >> n; 14 | std::cout << IfThenElse()(n > 0, 1, -1) << std::endl; 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /ch14/14.35.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | class PrintStr { 6 | public: 7 | std::string operator()(std::istream &is) { 8 | std::string s; 9 | if(std::getline(is, s)) 10 | return s; 11 | else 12 | return s; 13 | } 14 | }; 15 | 16 | int main() { 17 | PrintStr ps; 18 | std::vector vs; 19 | std::string s = ps(std::cin); 20 | while (!s.empty()) { 21 | vs.push_back(s); 22 | s = ps(std::cin); 23 | } 24 | for (const auto &l : vs) 25 | std::cout << "<" << l << ">" << std::endl; 26 | 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /ch14/14.36.md: -------------------------------------------------------------------------------- 1 | See [ex14.35](14.35.cpp). 2 | -------------------------------------------------------------------------------- /ch14/14.37.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct Equal { 6 | typedef int ty; 7 | Equal(ty v) : val(v) { } 8 | bool operator()(ty rhs) { 9 | return val == rhs; 10 | } 11 | private: 12 | ty val; 13 | }; 14 | 15 | int main() { 16 | std::vector vi { 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 17 | int oldVal, newVal; 18 | std::cin >> oldVal >> newVal; 19 | std::replace_if(vi.begin(), vi.end(), Equal(oldVal), newVal); 20 | for (const auto &i : vi) 21 | std::cout << i << " "; 22 | std::cout << std::endl; 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /ch14/14.38.in: -------------------------------------------------------------------------------- 1 | one two three four five 2 | 3 | 0123456789 01234567891 012345678912 4 | -------------------------------------------------------------------------------- /ch14/14.4.md: -------------------------------------------------------------------------------- 1 | (a) `%` should be nonmember 2 | 3 | (b) `%=` ought to be member 4 | 5 | (c) `++` should be member 6 | 7 | (d) `->` must be member 8 | 9 | (e) `<<` should be nonmember 10 | 11 | (f) `&&` should be nonmember 12 | 13 | (g) `==` should be nonmember 14 | 15 | (h) `()` must be member 16 | -------------------------------------------------------------------------------- /ch14/14.41.md: -------------------------------------------------------------------------------- 1 | Lambda is much shorter and simpler than defining a class with function-call operator when we want to use that function call at only one place. 2 | -------------------------------------------------------------------------------- /ch14/14.43.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | using namespace std::placeholders; 8 | int n; 9 | std::cin >> n; 10 | std::vector vi { 12, 34, 56, 78, 90, 123, 456, 789 }; 11 | auto it = std::find_if_not(vi.begin(), vi.end(), 12 | std::bind(std::modulus(), _1, n)); 13 | if (it != vi.end()) 14 | std::cout << n << " is divisible by " << *it << std::endl; 15 | else 16 | std::cout << "Find nothing." << std::endl; 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /ch14/14.46.md: -------------------------------------------------------------------------------- 1 | It is a bad idea to define conversion operators for `Sales_data` class, they should be defined as oridinary member functions to describe their usages. 2 | 3 | If we must define them, then they should be defined as `explicit` to avoid surprising results. 4 | -------------------------------------------------------------------------------- /ch14/14.47.md: -------------------------------------------------------------------------------- 1 | struct Integral { 2 | operator const int(); // covert `Integral` to `const int`, and may change the object itself 3 | operator int() const; // covert `Integral` to `int`, and will not change the object itself 4 | }; 5 | -------------------------------------------------------------------------------- /ch14/14.50.cpp: -------------------------------------------------------------------------------- 1 | struct LongDouble { 2 | LongDouble(double = 0.0); 3 | operator double(); 4 | operator float(); 5 | }; 6 | 7 | int main() { 8 | LongDouble ldObj; 9 | int ex1 = ldObj; // Error 10 | // Both convert to `double` and `float` are equally good match 11 | float ex2 = ldObj; // OK 12 | // match `operator float` 13 | 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /ch14/14.51.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct LongDouble { 4 | LongDouble(double = 0.0); 5 | operator double() { 6 | std::cout << "LongDouble::operator double()" << std::endl; 7 | return 0; 8 | } 9 | operator float() { 10 | std::cout << "LongDouble::operator float()" << std::endl; 11 | return 0; 12 | } 13 | }; 14 | void calc(int) { 15 | std::cout << "void calc(int)" << std::endl; 16 | } 17 | void calc(LongDouble) { 18 | std::cout << "void calc(LongDouble)" << std::endl; 19 | } 20 | 21 | int main() { 22 | double dval = 0; 23 | calc(dval); 24 | // will call `void calc(int)`, since only standard conversion is used 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /ch15/15.1.md: -------------------------------------------------------------------------------- 1 | A virtual member is a function that the base class expects its derived classes to override. When we call a virtual function through a pointer or reference to base class, the call will be dynamically bound to the virtual function of the dynamic type of the pointer or reference. 2 | -------------------------------------------------------------------------------- /ch15/15.10.md: -------------------------------------------------------------------------------- 1 | `ifstream` is inherited from `istream`. Thus, we can use objects of type `ifstream` as if they were `istream` objects. The parameter of `read` function is a reference to base type `istream`, the automatic derived-to-base conversion applies when we pass a derived type `ifstream` to that function. Inside `read` function, we can use the `istream` subpart in the `ifstream` object through the reference. 2 | -------------------------------------------------------------------------------- /ch15/15.13.md: -------------------------------------------------------------------------------- 1 | The derived virtual function `print` try to call the base version in its function body, but without the scope operator, the call will be resolved at run time as a call to the derived version itself, resulting in an infinite recursion. 2 | 3 | To fix this problem, we need to prefix the scope operator to the call like `base::print(os);`. 4 | -------------------------------------------------------------------------------- /ch15/15.16.md: -------------------------------------------------------------------------------- 1 | See [ex15.15](15.15.cpp). 2 | -------------------------------------------------------------------------------- /ch15/15.2.md: -------------------------------------------------------------------------------- 1 | A `protected` member in base class can be access by its derived class, while a `private` member cannot. 2 | -------------------------------------------------------------------------------- /ch15/15.20.md: -------------------------------------------------------------------------------- 1 | See [ex15.18](15.18.cpp) and [ex15.19](15.19.cpp). 2 | -------------------------------------------------------------------------------- /ch15/15.24.md: -------------------------------------------------------------------------------- 1 | A base class usually needs a virtual destructor to allow objects in the inheritance hierarchy to be dynamically allocated. The virtual destructor must free dynamically alloacted resources in its class if so, otherwise, an empty virtual destructor is enough. 2 | -------------------------------------------------------------------------------- /ch15/15.25.md: -------------------------------------------------------------------------------- 1 | Because if there exists any user-defined constructor, then there is no synthesized default constructor. And if we want to construct a default initialized `Bulk_quote` type object, all classes must have user-defined or synthesized default constructor in inheritance hierarchy. Thus we define a default constructor for `Disc_quote`. 2 | 3 | If we remove that constructor, the complier will not synthesized one for us, thus we could only create `Bulk_quote` object by providing arguments consistent with other constructors. 4 | -------------------------------------------------------------------------------- /ch15/15.33.md: -------------------------------------------------------------------------------- 1 | The `Query_base` class is an abstract class with no data member, we cannot create object of type `Query_base` directly, but we can create reference or pointer to `Query_base`. When we copy, move, assign or destroy reference or pointer, we actually copy, move, assign or destroy the underlying concrete class, what happens depends on the definitions of the underlying concrete class. 2 | -------------------------------------------------------------------------------- /ch15/15.35/QueryResult.cpp: -------------------------------------------------------------------------------- 1 | #include "QueryResult.h" 2 | 3 | std::string make_plural(int cnt, const std::string &s, 4 | const std::string &postfix = "s") { 5 | return cnt > 1 ? s + postfix : s; 6 | } 7 | 8 | std::ostream &print(std::ostream &os, const QueryResult &qr) { 9 | std::cout << "\"" << qr.word << "\" occurs " << qr.total << " " 10 | << make_plural(qr.total, "time") << ":\n"; 11 | for (const auto &ln : *qr.line_numbers) 12 | std::cout << "(line " << ln + 1 << ") " 13 | << *(qr.line_text->begin() + ln) << std::endl; 14 | return os; 15 | } 16 | -------------------------------------------------------------------------------- /ch15/15.35/Query_base.h: -------------------------------------------------------------------------------- 1 | #ifndef QUERY_BASE_H 2 | #define QUERY_BASE_H 3 | 4 | //class Query; // No need forward declaration for only friend declaration 5 | class QueryResult; 6 | 7 | #include 8 | #include "TextQuery.h" 9 | 10 | class Query_base { 11 | friend class Query; 12 | 13 | protected: 14 | using line_no_type = TextQuery::line_no_type; 15 | virtual ~Query_base() = default; 16 | 17 | private: 18 | virtual QueryResult eval(const TextQuery &) const = 0; 19 | virtual std::string rep() const = 0; 20 | }; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /ch15/15.35/TestQuery.cpp: -------------------------------------------------------------------------------- 1 | // Compile with parameter `/DDEBUG_LEVEL=1`(for Visual Studio) to enable print 2 | // for ex15.36. 3 | #include 4 | #include "Query.h" 5 | 6 | //#include "BinaryQuery.h" 7 | //#include "AndQuery.h" 8 | //#include "OrQuery.h" 9 | 10 | int main() { 11 | Query q = Query("fiery") & Query("bird") | Query("wind"); 12 | std::cout << "==================" << std::endl; 13 | std::cout << q << std::endl; 14 | 15 | //BinaryQuery a = Query("fiery") & Query("bird"); 16 | //AndQuery b = Query("fiery") & Query("bird"); 17 | //OrQuery c = Query("fiery") & Query("bird"); 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /ch15/15.35/TextQuery.h: -------------------------------------------------------------------------------- 1 | #ifndef TEXTQUERY_H 2 | #define TEXTQUERY_H 3 | 4 | class QueryResult; 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "StrVec.h" 12 | 13 | class TextQuery { 14 | public: 15 | using line_no_type = StrVec::size_type; 16 | 17 | explicit TextQuery(std::ifstream &in); 18 | 19 | QueryResult query(const std::string &word) const; 20 | 21 | private: 22 | std::shared_ptr text; 23 | std::map>> word_map; 24 | }; 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /ch15/15.35/text.in: -------------------------------------------------------------------------------- 1 | Alice Emma has long flowing red hair. 2 | Her Daddy says when the wind blows 3 | through her hair, it looks almost alive, 4 | like a fiery bird in flight. 5 | A beautiful fiery bird, he tells her, 6 | magical but untamed. 7 | "Daddy, shush, there is no such thing," 8 | she tells him, at the same time wanting 9 | him to tell her more. 10 | Shyly, she asks, "I mean, Daddy, is there?" 11 | 12 | This is a test for same words occurs on the same line. 13 | 14 | And different line. 15 | -------------------------------------------------------------------------------- /ch15/15.36.md: -------------------------------------------------------------------------------- 1 | See [ex15.35](15.35). 2 | -------------------------------------------------------------------------------- /ch15/15.37/QueryResult.cpp: -------------------------------------------------------------------------------- 1 | #include "QueryResult.h" 2 | 3 | std::string make_plural(int cnt, const std::string &s, 4 | const std::string &postfix = "s") { 5 | return cnt > 1 ? s + postfix : s; 6 | } 7 | 8 | std::ostream &print(std::ostream &os, const QueryResult &qr) { 9 | std::cout << "\"" << qr.word << "\" occurs " << qr.total << " " 10 | << make_plural(qr.total, "time") << ":\n"; 11 | for (const auto &ln : *qr.line_numbers) 12 | std::cout << "(line " << ln + 1 << ") " 13 | << *(qr.line_text->begin() + ln) << std::endl; 14 | return os; 15 | } 16 | -------------------------------------------------------------------------------- /ch15/15.37/TextQuery.h: -------------------------------------------------------------------------------- 1 | #ifndef TEXTQUERY_H 2 | #define TEXTQUERY_H 3 | 4 | class QueryResult; 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "StrVec.h" 12 | 13 | class TextQuery { 14 | public: 15 | using line_no_type = StrVec::size_type; 16 | 17 | explicit TextQuery(std::ifstream &in); 18 | 19 | QueryResult query(const std::string &word) const; 20 | 21 | private: 22 | std::shared_ptr text; 23 | std::map>> word_map; 24 | }; 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /ch15/15.37/text.in: -------------------------------------------------------------------------------- 1 | Alice Emma has long flowing red hair. 2 | Her Daddy says when the wind blows 3 | through her hair, it looks almost alive, 4 | like a fiery bird in flight. 5 | A beautiful fiery bird, he tells her, 6 | magical but untamed. 7 | "Daddy, shush, there is no such thing," 8 | she tells him, at the same time wanting 9 | him to tell her more. 10 | Shyly, she asks, "I mean, Daddy, is there?" 11 | 12 | This is a test for same words occurs on the same line. 13 | 14 | And different line. 15 | -------------------------------------------------------------------------------- /ch15/15.38.md: -------------------------------------------------------------------------------- 1 | All three declarations are illegal. We cannot directly create object of `BinaryQuery`, `AndQuery` or `OrQuery`. All these class are used for implementation, and they are not part of the interface. User code cannot use them directly, because all members of these class are not `public`, including constructors. Meanwhile, there is not constructor for class `BinaryQuery`, `AndQuery` or `OrQuery` that takes a `shared_ptr` as parameter. 2 | -------------------------------------------------------------------------------- /ch15/15.39/QueryResult.cpp: -------------------------------------------------------------------------------- 1 | #include "QueryResult.h" 2 | 3 | std::string make_plural(int cnt, const std::string &s, 4 | const std::string &postfix = "s") { 5 | return cnt > 1 ? s + postfix : s; 6 | } 7 | 8 | std::ostream &print(std::ostream &os, const QueryResult &qr) { 9 | std::cout << "\"" << qr.word << "\" occurs " << qr.total << " " 10 | << make_plural(qr.total, "time") << ":\n"; 11 | for (const auto &ln : *qr.line_numbers) 12 | std::cout << "(line " << ln + 1 << ") " 13 | << *(qr.line_text->begin() + ln) << std::endl; 14 | return os; 15 | } 16 | -------------------------------------------------------------------------------- /ch15/15.39/Query_base.h: -------------------------------------------------------------------------------- 1 | #ifndef QUERY_BASE_H 2 | #define QUERY_BASE_H 3 | 4 | //class Query; // No need forward declaration for only friend declaration 5 | class QueryResult; 6 | 7 | #include 8 | #include "TextQuery.h" 9 | 10 | class Query_base { 11 | friend class Query; 12 | 13 | protected: 14 | using line_no_type = TextQuery::line_no_type; 15 | virtual ~Query_base() = default; 16 | 17 | private: 18 | virtual QueryResult eval(const TextQuery &) const = 0; 19 | virtual std::string rep() const = 0; 20 | }; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /ch15/15.39/TextQuery.h: -------------------------------------------------------------------------------- 1 | #ifndef TEXTQUERY_H 2 | #define TEXTQUERY_H 3 | 4 | class QueryResult; 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "StrVec.h" 12 | 13 | class TextQuery { 14 | public: 15 | using line_no_type = StrVec::size_type; 16 | 17 | explicit TextQuery(std::ifstream &in); 18 | 19 | QueryResult query(const std::string &word) const; 20 | 21 | private: 22 | std::string filter_str(const std::string &) const; 23 | std::shared_ptr text; 24 | std::map>> word_map; 25 | }; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /ch15/15.39/text.in: -------------------------------------------------------------------------------- 1 | Alice Emma has long flowing red hair. 2 | Her Daddy says when the wind blows 3 | through her hair, it looks almost alive, 4 | like a fiery bird in flight. 5 | A beautiful fiery bird, he tells her, 6 | magical but untamed. 7 | "Daddy, shush, there is no such thing," 8 | she tells him, at the same time wanting 9 | him to tell her more. 10 | Shyly, she asks, "I mean, Daddy, is there?" 11 | 12 | This is a test for same words occurs on the same line. 13 | 14 | And different line. 15 | -------------------------------------------------------------------------------- /ch15/15.4.md: -------------------------------------------------------------------------------- 1 | (a) `class Derived : public Derived { ... };` Incorrect, it is impossible to derive a class from itself. 2 | 3 | (b) `class Derived : private Base { ... };` This is not only a declaration, but also a definition. 4 | 5 | (c) `class Derived : public Base;` Incorrect. The declaration of a derived class contains the class name but does not include its derivation list. 6 | -------------------------------------------------------------------------------- /ch15/15.40.md: -------------------------------------------------------------------------------- 1 | > In the `OrQuery` `eval` function what would happen if its `rhs` member returned an empty set? What if its `lhs` member did so? What if both `rhs` and `lhs` returned empty sets? 2 | 3 | If its `rhs` member returned an empty set, then the `insert` function would insert no element into the `ret_lines`. 4 | 5 | If its `lhs` member returned an empty set, then the `ret_lines` would be initialized as an empty set. 6 | 7 | If both `rhs` and `lhs` returned empty sets, then the `ret_lines` would also be an empty set. 8 | 9 | -------------------------------------------------------------------------------- /ch15/15.41/QueryResult.cpp: -------------------------------------------------------------------------------- 1 | #include "QueryResult.h" 2 | 3 | std::string make_plural(int cnt, const std::string &s, 4 | const std::string &postfix = "s") { 5 | return cnt > 1 ? s + postfix : s; 6 | } 7 | 8 | std::ostream &print(std::ostream &os, const QueryResult &qr) { 9 | std::cout << "\"" << qr.word << "\" occurs " << qr.total << " " 10 | << make_plural(qr.total, "time") << ":\n"; 11 | for (const auto &ln : *qr.line_numbers) 12 | std::cout << "(line " << ln + 1 << ") " 13 | << *(qr.line_text->begin() + ln) << std::endl; 14 | return os; 15 | } 16 | -------------------------------------------------------------------------------- /ch15/15.41/Query_base.h: -------------------------------------------------------------------------------- 1 | #ifndef QUERY_BASE_H 2 | #define QUERY_BASE_H 3 | 4 | //class Query; // No need forward declaration for only friend declaration 5 | class QueryResult; 6 | 7 | #include 8 | #include "TextQuery.h" 9 | 10 | class Query_base { 11 | friend class Query; 12 | 13 | protected: 14 | using line_no_type = TextQuery::line_no_type; 15 | virtual ~Query_base() = default; 16 | 17 | private: 18 | virtual QueryResult eval(const TextQuery &) const = 0; 19 | virtual std::string rep() const = 0; 20 | }; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /ch15/15.41/TextQuery.h: -------------------------------------------------------------------------------- 1 | #ifndef TEXTQUERY_H 2 | #define TEXTQUERY_H 3 | 4 | class QueryResult; 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "StrVec.h" 12 | 13 | class TextQuery { 14 | public: 15 | using line_no_type = StrVec::size_type; 16 | 17 | explicit TextQuery(std::ifstream &in); 18 | 19 | QueryResult query(const std::string &word) const; 20 | 21 | private: 22 | std::string filter_str(const std::string &) const; 23 | std::shared_ptr text; 24 | std::map>> word_map; 25 | }; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /ch15/15.41/text.in: -------------------------------------------------------------------------------- 1 | Alice Emma has long flowing red hair. 2 | Her Daddy says when the wind blows 3 | through her hair, it looks almost alive, 4 | like a fiery bird in flight. 5 | A beautiful fiery bird, he tells her, 6 | magical but untamed. 7 | "Daddy, shush, there is no such thing," 8 | she tells him, at the same time wanting 9 | him to tell her more. 10 | Shyly, she asks, "I mean, Daddy, is there?" 11 | 12 | This is a test for same words occurs on the same line. 13 | 14 | And different line. 15 | -------------------------------------------------------------------------------- /ch15/15.5.md: -------------------------------------------------------------------------------- 1 | See [ex15.3](15.3.cpp). 2 | -------------------------------------------------------------------------------- /ch15/15.6.md: -------------------------------------------------------------------------------- 1 | See [ex15.3](15.3.cpp). 2 | -------------------------------------------------------------------------------- /ch15/15.8.md: -------------------------------------------------------------------------------- 1 | The **static type** is the type with which a variable is declared or that an expression yields. It is always known at compile time. 2 | 3 | The **dynamic type** is the type of the object in memory that the variable or expression represents. It is not known until run time. The dynamic type of an expression that is neither a reference nor a pointer is always the same as that expression's static type. 4 | -------------------------------------------------------------------------------- /ch15/15.9.md: -------------------------------------------------------------------------------- 1 | The dynamic type of an expression that is either a reference or a pointer could be different from that expression's static type. 2 | 3 | class Base { /* ... */ }; 4 | class Derived : public Base { /* ... */ }; 5 | Derived d; 6 | Base *bp = &d; 7 | Base &br = d; 8 | Derived *dp = &d; 9 | Base *bp2 = dp; 10 | 11 | `bp2`, `bp` and `br` have different static type and dynamic type. 12 | -------------------------------------------------------------------------------- /ch16/16.1.md: -------------------------------------------------------------------------------- 1 | Instantiating a template is the process in which 2 | 3 | 1. the compiler uses the argument(s) of the call to deduce the template parameter(s), 4 | 2. the compiler uses the deduced template parameter(s) to create a specific version (new "instance") of the template using the actual argument(s) in place of the corresponding template parameter(s). 5 | 6 | Instantiation of a template is the compiler-generated specific version (with the actual argument) of the template. 7 | -------------------------------------------------------------------------------- /ch16/16.10.md: -------------------------------------------------------------------------------- 1 | When a class template is instantiated, the compiler uses explicitly provided template argument(s) generating type-specific version of the class template. 2 | -------------------------------------------------------------------------------- /ch16/16.11.cpp: -------------------------------------------------------------------------------- 1 | template class ListItem; 2 | template class List { 3 | public: 4 | List(); 5 | List(const List &); 6 | List& operator=(const List &); 7 | ~List(); 8 | //void insert(ListItem *ptr, elemType value); // error: should specify type 9 | void insert(ListItem *ptr, elemType value); 10 | private: 11 | //ListItem *front, *end; // error: should specify type 12 | ListItem *front, *end; 13 | }; 14 | 15 | int main() { 16 | List l; 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /ch16/16.13.md: -------------------------------------------------------------------------------- 1 | I choose one-to-one friendship between corresponding instantiations of class and its friend. Because we don't want classes with different template parameter type being friend with each other. 2 | -------------------------------------------------------------------------------- /ch16/16.15.md: -------------------------------------------------------------------------------- 1 | See [ex16.14](16.14.cpp). 2 | -------------------------------------------------------------------------------- /ch16/16.17.md: -------------------------------------------------------------------------------- 1 | When used in template type parameter declaration, keywords `typename` and `class` have no difference. 2 | 3 | When we use the scope operator (`::`) to access type members of a class template, we must use keyword `typename`. 4 | -------------------------------------------------------------------------------- /ch16/16.19.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | void print(const C &c) { 7 | for (typename C::size_type i = 0; i != c.size(); ++i) 8 | std::cout << c[i] << " "; 9 | std::cout << std::endl; 10 | } 11 | 12 | int main() { 13 | std::vector vi { 1, 2, 3, 4, 5 }; 14 | std::vector vd { 1.1, 2.2, 3.3, 4.4, 5.5 }; 15 | std::deque di { 1, 2, 3, 4, 5 }; 16 | 17 | print(vi); 18 | print(vd); 19 | print(di); 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /ch16/16.22/DebugDelete.h: -------------------------------------------------------------------------------- 1 | #ifndef DEBUGDELETE_H 2 | #define DEBUGDELETE_H 3 | 4 | #include 5 | 6 | class DebugDelete { 7 | public: 8 | DebugDelete(std::ostream &s = std::cerr) : os(s) { } 9 | 10 | template void operator()(T *p) const { 11 | os << "deleting pointer " << typeid(p).name() << std::endl; 12 | delete p; 13 | } 14 | 15 | private: 16 | std::ostream &os; 17 | }; 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /ch16/16.22/QueryResult.cpp: -------------------------------------------------------------------------------- 1 | #include "QueryResult.h" 2 | 3 | std::string make_plural(int cnt, const std::string &s, 4 | const std::string &postfix = "s") { 5 | return cnt > 1 ? s + postfix : s; 6 | } 7 | 8 | std::ostream &print(std::ostream &os, const QueryResult &qr) { 9 | std::cout << "\"" << qr.word << "\" occurs " << qr.total << " " 10 | << make_plural(qr.total, "time") << ":\n"; 11 | for (const auto &ln : *qr.line_numbers) 12 | std::cout << "(line " << ln + 1 << ") " 13 | << *(qr.line_text->begin() + ln) << std::endl; 14 | return os; 15 | } 16 | -------------------------------------------------------------------------------- /ch16/16.22/Query_base.h: -------------------------------------------------------------------------------- 1 | #ifndef QUERY_BASE_H 2 | #define QUERY_BASE_H 3 | 4 | //class Query; // No need forward declaration for only friend declaration 5 | class QueryResult; 6 | 7 | #include 8 | #include "TextQuery.h" 9 | 10 | class Query_base { 11 | friend class Query; 12 | 13 | protected: 14 | using line_no_type = TextQuery::line_no_type; 15 | virtual ~Query_base() = default; 16 | 17 | private: 18 | virtual QueryResult eval(const TextQuery &) const = 0; 19 | virtual std::string rep() const = 0; 20 | }; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /ch16/16.22/TextQuery.h: -------------------------------------------------------------------------------- 1 | #ifndef TEXTQUERY_H 2 | #define TEXTQUERY_H 3 | 4 | class QueryResult; 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "StrVec.h" 12 | 13 | class TextQuery { 14 | public: 15 | using line_no_type = StrVec::size_type; 16 | 17 | explicit TextQuery(std::ifstream &in); 18 | 19 | QueryResult query(const std::string &word) const; 20 | 21 | private: 22 | std::string filter_str(const std::string &) const; 23 | std::shared_ptr text; 24 | std::map>> word_map; 25 | }; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /ch16/16.22/text.in: -------------------------------------------------------------------------------- 1 | Alice Emma has long flowing red hair. 2 | Her Daddy says when the wind blows 3 | through her hair, it looks almost alive, 4 | like a fiery bird in flight. 5 | A beautiful fiery bird, he tells her, 6 | magical but untamed. 7 | "Daddy, shush, there is no such thing," 8 | she tells him, at the same time wanting 9 | him to tell her more. 10 | Shyly, she asks, "I mean, Daddy, is there?" 11 | 12 | This is a test for same words occurs on the same line. 13 | 14 | And different line. 15 | -------------------------------------------------------------------------------- /ch16/16.23.md: -------------------------------------------------------------------------------- 1 | The call operator will be excuted when all `shared_ptr`s pointing to the same data have been destroyed. See [ex16.22](16.22). 2 | -------------------------------------------------------------------------------- /ch16/16.25.md: -------------------------------------------------------------------------------- 1 | extern template class vector; 2 | 3 | This is a template instantiation declaration. It means that there will be a non`extern` use of this instantiation elsewhere in the program. 4 | 5 | template class vector; 6 | 7 | This is a template instantiation definition. It will instantiate all members of template `vector`. 8 | -------------------------------------------------------------------------------- /ch16/16.26.md: -------------------------------------------------------------------------------- 1 | No. Because a template `vector` instantiation definition will instantiate all members of template `vector`, including member functions whose default argument is the default constructor of the template parameter type. 2 | -------------------------------------------------------------------------------- /ch16/16.5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | void print(const T (&arr)[N]) { 5 | for (size_t i = 0; i != N; ++i) 6 | std::cout << arr[i] << std::endl; 7 | } 8 | 9 | struct C { 10 | int i; 11 | double d; 12 | }; 13 | 14 | std::ostream &operator<<(std::ostream &os, const C &c) { 15 | return os << c.i << " " << c.d; 16 | } 17 | 18 | int main() { 19 | int a[] = { 1, 2, 3, 4 }; 20 | print(a); 21 | 22 | char b[] = "abcde"; 23 | print(b); // will print the trailing `\0` 24 | 25 | C c[] = { 1, 1.1, 2, 2.2, 3, 3.3 }; 26 | print(c); 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /ch16/16.6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | T *begin_arr(T (&arr)[N]) { 5 | return arr; 6 | } 7 | 8 | template 9 | T *end_arr(T (&arr)[N]) { 10 | return arr + N; 11 | } 12 | 13 | int main() { 14 | int arr[] = { 1, 2, 3, 4, 5 }; 15 | for (auto it = begin_arr(arr); it != end_arr(arr); ++it) 16 | std::cout << *it << std::endl; 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /ch16/16.7.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | constexpr size_t size_arr(T (&arr)[N]) { 5 | return N; 6 | } 7 | 8 | 9 | int main() { 10 | int arr[] = { 1, 2, 3, 4, 5 }; 11 | constexpr size_t sz = size_arr(arr); 12 | 13 | std::cout << sz << " " << size_arr(arr) << std::endl; 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /ch16/16.8.md: -------------------------------------------------------------------------------- 1 | The `operator!=` is defined by iterators for all library containers, but the `operator<` is not. By using `operator!=` inside template definition, the template can be used by all library containers. 2 | -------------------------------------------------------------------------------- /ch16/16.9.md: -------------------------------------------------------------------------------- 1 | A **function template** is a blueprint used by compiler for generating type-specific fuctions. The compiler ordinarily deduces the template parameter(s) using the arguments of the call. 2 | 3 | A **class template** is a blueprint used by compiler for generating type-specific classes. The compiler cannot deduce the template parameter(s) for a class template. 4 | -------------------------------------------------------------------------------- /ch2/2.10.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | std::string global_str; // Empty string object 4 | int global_int; // 0 5 | int main() { 6 | int local_int; // Undefined value 7 | std::string local_str; // Empty string object 8 | 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /ch2/2.11.cpp: -------------------------------------------------------------------------------- 1 | extern int ix = 1024; // Definition 2 | int iy; // Definition 3 | extern int iz; // Declaration 4 | int main() { 5 | //extern int ix2 = 1024; // Error 6 | int iy2; // Definition 7 | extern int iz2; // Declaration 8 | 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /ch2/2.12.cpp: -------------------------------------------------------------------------------- 1 | int _; // Error: start with `_` (May not warn by compiler) 2 | int main() { 3 | //int double = 3.14; // Error: reserved key word 4 | int _; // OK 5 | //int catch-22; // Error: `-` in name 6 | //int 1_or_2 = 1; // Error: start with number 7 | double Double = 3.14; // OK 8 | 9 | int _i2; // OK 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /ch2/2.13.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int i = 42; 4 | int main() { 5 | int i = 100; 6 | int j = i; // 100 7 | std::cout << j << std::endl; 8 | 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /ch2/2.14.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int i = 100, sum = 0; 5 | for (int i = 0; i != 10; ++i) 6 | sum += i; 7 | std::cout << i << " " << sum << std::endl; // 100 45 8 | 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /ch2/2.15.cpp: -------------------------------------------------------------------------------- 1 | int main() { 2 | int ival = 1.01; // OK 3 | //int &rval1 = 1.01; // Error: initializer must be `int` object 4 | int &rval2 = ival; // OK 5 | //int &rval3; // Error: a reference must be initialized when defined 6 | 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /ch2/2.16.cpp: -------------------------------------------------------------------------------- 1 | int main() { 2 | int i = 0, &r1 = i; 3 | double d = 0, &r2 = d; 4 | 5 | r2 = 3.14159; // d = 3.14159 6 | r2 = r1; // d = i 7 | i = r2; // i = d 8 | r1 = d; // i = d 9 | 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /ch2/2.17.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int i, &ri = i; 5 | i = 5; 6 | ri = 10; 7 | std::cout << i << " " << ri << std::endl; // 10 10 8 | 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /ch2/2.18.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int i; 5 | int *ip = &i; 6 | 7 | *ip = 10; 8 | std::cout << i << " " << *ip << std::endl; // 10 10 9 | i = 5; 10 | std::cout << i << " " << *ip << std::endl; // 5 5 11 | 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /ch2/2.19.md: -------------------------------------------------------------------------------- 1 | A pointer is an object whose value is the adress of another object. 2 | 3 | A reference is not an object. It is an alias of another object. 4 | -------------------------------------------------------------------------------- /ch2/2.2.md: -------------------------------------------------------------------------------- 1 | Rate: `float`, principal: `long long`, payment: `long long`. 2 | 3 | The rate is usually a floating-point number with 4 significant digits. The principal and payment are integral usually less than 1 trillion. 4 | -------------------------------------------------------------------------------- /ch2/2.20.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int i = 42; 5 | int *p1 = &i; 6 | *p1 = *p1 * *p1; // i = i * i 7 | std::cout << i << std::endl; 8 | 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /ch2/2.21.cpp: -------------------------------------------------------------------------------- 1 | int main () { 2 | int i = 0; 3 | 4 | //double *dp = &i; // Error: `dp` can only hold pointer to `double` 5 | //int *ip = i; // Error: a pointer can only hold address to object 6 | int *p = &i; // OK 7 | 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /ch2/2.22.md: -------------------------------------------------------------------------------- 1 | `if (p)` means if the pointer `p` is not null. 2 | 3 | `if (*p)` means if the object pointed by the pointer is not false (which means the object is not null or zero etc.). 4 | -------------------------------------------------------------------------------- /ch2/2.23.md: -------------------------------------------------------------------------------- 1 | No, you can't. Because it would be expensive to maintain meta data about what constitutes a valid pointer and what doesn't, and in C++ you don't pay for what you don't want. 2 | 3 | See answer [here](http://stackoverflow.com/a/17202622/5340808). 4 | 5 | However, a *smart pointer* can be used to tell if it points to a valid object. 6 | -------------------------------------------------------------------------------- /ch2/2.24.cpp: -------------------------------------------------------------------------------- 1 | int main() { 2 | int i = 42; 3 | void *p = &i; // OK, a `void *` pointer can point to any type 4 | //long *lp = &i; // Error, a `long *` pointer can not point to `int *` 5 | 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /ch2/2.26.cpp: -------------------------------------------------------------------------------- 1 | int main() { 2 | //const int buf; // Error: must be initialized 3 | int cnt = 0; // OK 4 | const int sz = cnt; // OK 5 | ++cnt; // OK 6 | //++sz; // Error: cannot change the value of a const variable 7 | 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /ch2/2.28.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | //(a) 5 | //int i, *const cp; // Error: a const pointer must be initialized 6 | //(b) 7 | //int *p1, *const p2; // Error: a const pointer must be initialized 8 | //(c) 9 | //const int ic, &r = ic; // Error: const int `ic` must be initialized 10 | //(d) 11 | //const int *const p3; // Error: a const pointer must be initialized 12 | //(e) 13 | const int *p; // OK 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /ch2/2.29.cpp: -------------------------------------------------------------------------------- 1 | int main() { 2 | int i, *const cp = &i; 3 | int *p1, *const p2 = p1; 4 | const int ic = 5, &r = ic; 5 | const int *const p3 = ⁣ 6 | const int *p; 7 | 8 | i = ic; // OK 9 | p1 = p3; // Error: low-level const doesn't match 10 | p1 = ⁣ // Error: low-level const doesn't match 11 | p3 = ⁣ // Error: cannot assign value to a const variable 12 | p2 = p1; // Error: cannot assign value to a const variable 13 | ic = *p3; // Error: cannot assign value to a const variable 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /ch2/2.3.md: -------------------------------------------------------------------------------- 1 | See [ex2.4](2.4.cpp). 2 | -------------------------------------------------------------------------------- /ch2/2.30.cpp: -------------------------------------------------------------------------------- 1 | int main() { 2 | int i; 3 | const int v2 = 0; // v2 has top-level const 4 | int v1 = v2; 5 | int *p1 = &v1, &r1 = v1; 6 | const int *p2 = &v2, *const p3 = &i, &r2 = v2; // p2 has low-level const 7 | // p3 has both low-level and top-level const 8 | // r2 has low-level const 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /ch2/2.32.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | //int null = 0, *p = null; // Error: type mismatch 5 | 6 | // Method 1 7 | const int null1 = 0; 8 | int *p1 = null1; 9 | 10 | // Method 2 11 | int *p2 = nullptr; 12 | 13 | // Method 3 14 | int *p3 = 0; 15 | 16 | // Method 4 (may need include `cstdlib`) 17 | int *p4 = NULL; 18 | 19 | // Method 5 20 | constexpr int null2 = 0; 21 | int *p5 = null2; 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /ch2/2.33.md: -------------------------------------------------------------------------------- 1 | See [ex2.34](2.34.cpp). 2 | -------------------------------------------------------------------------------- /ch2/2.35.cpp: -------------------------------------------------------------------------------- 1 | int main() { 2 | const int i = 42; // const int 3 | auto j = 1; // int 4 | const auto &k = i; // const int & 5 | auto *p = &i; // const int * 6 | const auto j2 = i, &k2 = i; // const int, const int & 7 | 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /ch2/2.36.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int a = 3, b = 4; 5 | decltype(a) c = a; // `c` is `int` 6 | decltype((b)) d = a; // `d` is `int &` to a 7 | std::cout << a << " " << b << " " << c << " " << d << std::endl; // 3 4 3 3 8 | ++c; 9 | std::cout << a << " " << b << " " << c << " " << d << std::endl; // 3 4 4 3 10 | ++d; 11 | std::cout << a << " " << b << " " << c << " " << d << std::endl; // 4 4 4 4 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /ch2/2.37.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int a = 3, b = 4; 5 | decltype(a) c = a; // `c` is `int` 6 | decltype(a = b) d = a; // `d` is `int &` to a, the expression is not evaluated 7 | std::cout << a << " " << b << " " << c << " " << d << std::endl; // 3 4 3 3 8 | 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /ch2/2.38.md: -------------------------------------------------------------------------------- 1 | `auto` will ignore the top-level `const` qualifier and reference. 2 | 3 | `decltype` will include top-level `const` and reference. 4 | 5 | Same type 6 | 7 | int i; 8 | auto a1 = i; // int 9 | decltype(i) d1; // int 10 | 11 | Different type 12 | 13 | int i, &j = i; 14 | auto a2 = j; // int 15 | decltype(j) d2; // int & 16 | 17 | const int i; 18 | auto a3 = i; // int 19 | decltype(i) d3 = 42; // const int 20 | -------------------------------------------------------------------------------- /ch2/2.39.cpp: -------------------------------------------------------------------------------- 1 | //struct Foo { /* empty */ } // Error: lack semicolon 2 | int main() { 3 | return 0; 4 | } 5 | -------------------------------------------------------------------------------- /ch2/2.40.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Sales_data { 4 | std::string bookNo; 5 | unsigned units_sold = 0; 6 | double revenue = 0.0; 7 | }; 8 | 9 | int main() { 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /ch2/2.6.cpp: -------------------------------------------------------------------------------- 1 | int main() { 2 | int month = 9, day = 7; // OK 3 | int month1 = 09, day1 = 07; // Error: the digit of octal integral literal should in range 0~7 4 | 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /ch2/2.7.cpp: -------------------------------------------------------------------------------- 1 | int main() { 2 | "Who goes with F\145rgus?\012"; // character string literal containing two octal escape sequences 3 | 3.14e1L; // floating-point literal, type is `long double` 4 | 1024f; // floating-point literal, type is `float` 5 | 3.14L; // floating-point literal, type is `long double` 6 | 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /ch2/2.8.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | std::cout << ">" << "2M\n" << "<" << std::endl; 5 | std::cout << ">" << "2\tM\n" << "<" << std::endl; 6 | 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /ch2/2.9.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main () { 4 | // (a) 5 | //std::cin >> int input_value; // Error: variable must be defined before using for input 6 | int input_value; 7 | std::cin >> input_value; 8 | 9 | // (b) 10 | //int i = { 3.14 }; // Error: loss information in list initialization 11 | double d = { 3.14 }; // OK 12 | double d2 = { 3 }; // OK 13 | 14 | // (c) 15 | //double salary = wage = 9999.99; // Error 16 | double salary, wage; 17 | salary = wage = 9999.99; 18 | 19 | // (d) 20 | int i2 = 3.14; // OK, `i2` is 3 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /ch2/Sales_data.h: -------------------------------------------------------------------------------- 1 | #ifndef SALES_DATA_H 2 | #define SALES_DATA_H 3 | 4 | #include 5 | 6 | struct Sales_data { 7 | std::string bookNo; 8 | unsigned units_sold = 0; 9 | double revenue = 0.0; 10 | }; 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /ch3/3.10.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::string s; 6 | std::cin >> s; 7 | for (const auto &c : s) 8 | if (!ispunct(c)) 9 | std::cout << c; 10 | std::cout << std::endl; 11 | 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /ch3/3.11.md: -------------------------------------------------------------------------------- 1 | The range `for` is legal. The type of `c` is `const char &`. 2 | -------------------------------------------------------------------------------- /ch3/3.12.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::vector> ivec; 6 | // OK, a vector of vector of int, similar to 2-d int array 7 | //std::vector svec = ivec; 8 | // Error: the type of `svec` and `ivec` doesn't match 9 | std::vector svec2(10, "null"); 10 | // OK, a vector of ten strings whose value are all "null" 11 | 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /ch3/3.13.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using std::vector; 4 | using std::string; 5 | 6 | int main() { 7 | vector v1; // 0 element 8 | vector v2(10); // 10 elements, values are all 0 9 | vector v3(10, 42); // 10 elements, values are all 42 10 | vector v4{10}; // 1 element, value is 10 11 | vector v5{10, 42}; // 2 elements, values are 10 and 42 12 | vector v6{10}; // 10 elements, values are all empty string 13 | vector v7{10, "hi"}; // 10 elements, values are all "hi" 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /ch3/3.14.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::vector iv; 6 | int i; 7 | while (std::cin >> i) 8 | iv.push_back(i); 9 | for (const auto & k : iv) 10 | std::cout << k << " "; 11 | std::cout << std::endl; 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /ch3/3.15.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::vector sv; 7 | std::string s; 8 | while (std::cin >> s) 9 | sv.push_back(s); 10 | for (const auto & k : sv) 11 | std::cout << k << " "; 12 | std::cout << std::endl; 13 | 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /ch3/3.15.in: -------------------------------------------------------------------------------- 1 | osidaf 2 | 2e o[ih2 22340 3 | oisj ;asdij a;owie j0 234 wlkjd 4 | aosid 2 209 w;oi fadsd' 5 | 6 | da 7 | 8 | 9 | faoi294 10 | -------------------------------------------------------------------------------- /ch3/3.17.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::vector sv; 7 | std::string s; 8 | while (std::cin >> s) 9 | sv.push_back(s); 10 | for (auto &elem : sv) 11 | for (auto &c : elem) 12 | c = toupper(c); 13 | for (decltype(sv.size()) i = 0; i != sv.size(); ++i) { 14 | std::cout << sv[i] << '\t'; 15 | if ((i + 1) % 8 == 0) 16 | std::cout << std::endl; 17 | } 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /ch3/3.17.in: -------------------------------------------------------------------------------- 1 | aow; fn;209cd n;oiOAIa; pawi j02 2 | fw 3 | f2 ih029 hj awefipj'o2f2 4 | f 'oi h0-f 9ddno29c/)(*@N: wdjn 5 | 6 | 7 | 0w9f-92fkdm odif02 wji 2 8 | 2f 0j dko;HOC-0 wj=1 ;ma 9 | -------------------------------------------------------------------------------- /ch3/3.18.md: -------------------------------------------------------------------------------- 1 | Not legal. Use `ivec.push_back(42);` instead. 2 | -------------------------------------------------------------------------------- /ch3/3.19.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using std::vector; 3 | 4 | int main() { 5 | vector v1(10, 42); 6 | vector v2{42, 42, 42, 42, 42, 42, 42, 42, 42, 42}; 7 | vector v3; 8 | for (int i = 0; i != 10; ++i) 9 | v3.push_back(42); 10 | 11 | // The way with parentheses is prefered here. It contains less code. 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /ch3/3.2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void read_lines() { 5 | std::string line; 6 | while (getline(std::cin, line)) 7 | std::cout << line << std::endl; 8 | } 9 | 10 | void read_words() { 11 | std::string word; 12 | while (std::cin >> word) 13 | std::cout << word << std::endl; 14 | } 15 | 16 | int main() { 17 | //read_lines(); 18 | //read_words(); 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /ch3/3.22.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::vector text; 7 | 8 | std::string line; 9 | while (getline(std::cin, line)) 10 | text.push_back(line); 11 | 12 | for (auto it = text.begin(); it != text.end() && !it->empty(); ++it) 13 | for (auto &c : *it) 14 | c = toupper(c); 15 | 16 | for (auto &elem : text) 17 | if (elem.empty()) 18 | std::cout << std::endl; 19 | else 20 | std::cout << elem << " "; 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /ch3/3.23.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::vector iv(10); 6 | for (int i = 0; i != 10; ++i) 7 | std::cin >> iv[i]; 8 | for (auto it = iv.begin(); it != iv.end(); ++it) 9 | *it *= 2; 10 | for (const auto & elem : iv) 11 | std::cout << elem << " "; 12 | std::cout << std::endl; 13 | 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /ch3/3.25.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::vector scores(11, 0); 6 | unsigned grade; 7 | while (std::cin >> grade) 8 | ++*(scores.begin() + grade / 10); 9 | for (const auto & elem : scores) 10 | std::cout << elem << ' '; 11 | std::cout << std::endl; 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /ch3/3.26.md: -------------------------------------------------------------------------------- 1 | First, there is no operator `+` for two iterators. Second, for arithmetic types, using `mid = (beg + end) / 2` may lead to overflow. 2 | -------------------------------------------------------------------------------- /ch3/3.27.cpp: -------------------------------------------------------------------------------- 1 | int txt_size(); 2 | 3 | int main() { 4 | unsigned buf_size = 1024; 5 | 6 | //int ia1[buf_size]; // Error: `buf_size` must be `constexpr` 7 | int ia2[4 * 7 - 14]; // OK 8 | //int ia3[txt_size()]; // Error: `txt_size()` must be a `constexpr` function 9 | //char st[11] = "fundamental"; // Error: the size of string is 12 with a trailing '\0' 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /ch3/3.28.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using std::string; 3 | 4 | string sa[10]; // ten elements of empty string 5 | int ia[10]; // ten elements of 0 6 | 7 | int main() { 8 | string sa2[10]; // ten elements of empty string 9 | int ia2[10]; // ten elements of undefined value 10 | } 11 | -------------------------------------------------------------------------------- /ch3/3.29.md: -------------------------------------------------------------------------------- 1 | - The size of the array is fixed and must be known when defined. 2 | - Character array needs to leave space for null character at the end. 3 | - Arrays can not be copied or assigned as a whole. 4 | - Array can not be constructed with the same values like the constructor of vector when defined. 5 | - The size of array must be calculated when using (sometimes cannot be calculated at all) instead of calling a `size()` method. 6 | -------------------------------------------------------------------------------- /ch3/3.3.md: -------------------------------------------------------------------------------- 1 | *Whitespace characters* include space, newline and tab. 2 | 3 | The `string` input operator `<<` will regard all three kinds of whitespace characters as delimiter, so the string read from the operator will contain no whitespace characters. 4 | 5 | The `getline` function will regard only the newline character as delimiter, so the string read from `getline` function will contain no newline character but may contain space or tab. 6 | -------------------------------------------------------------------------------- /ch3/3.30.cpp: -------------------------------------------------------------------------------- 1 | int main() { 2 | constexpr size_t array_size = 10; 3 | int ia[array_size]; // index from `0` to `array_size - 1` 4 | //for (size_t ix = 1; ix <= array_size; ++ix) 5 | // ia[ix] = ix; 6 | for (size_t ix = 0; ix < array_size; ++ix) 7 | ia[ix] = ix + 1; 8 | 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /ch3/3.31.cpp: -------------------------------------------------------------------------------- 1 | int main() { 2 | int ia[10]; 3 | for (size_t i = 0; i != 10; ++i) 4 | ia[i] = i; 5 | 6 | // To get the size of an array one could use 7 | // sz = sizeof(ia) / sizeof(*ia) 8 | // However, this will not work for some situations like dynamically allocated 9 | // array, pointer array, array in function parameter etc. 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /ch3/3.32.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int ia[10]; 5 | for (size_t i = 0; i != 10; ++i) 6 | ia[i] = i; 7 | 8 | int ia2[10]; 9 | for (size_t i = 0; i != 10; ++i) 10 | ia2[i] = ia[i]; 11 | 12 | std::vector iv; 13 | for (int i = 0; i != 10; ++i) 14 | iv.push_back(i); 15 | 16 | std::vector iv2(iv); 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /ch3/3.33.md: -------------------------------------------------------------------------------- 1 | If the `scores` array was defined inside a function, then the value of each element is undefined. If the `scores` array was defined outside any function, then the value of each element is 0. 2 | -------------------------------------------------------------------------------- /ch3/3.34.md: -------------------------------------------------------------------------------- 1 | The code move `p1` to `p2`, it is the same with `p1 = p2`. 2 | 3 | Any values are legal as long as both `p1` and `p2` point to elements in the same array. 4 | -------------------------------------------------------------------------------- /ch3/3.35.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | int ia[10]; 6 | for (const auto &e : ia) 7 | std::cout << e << ' '; 8 | std::cout << std::endl; 9 | 10 | for (int *bg = std::begin(ia), *ed = std::end(ia); bg != ed; ++bg) 11 | *bg = 0; 12 | 13 | for (const auto &e : ia) 14 | std::cout << e << ' '; 15 | std::cout << std::endl; 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /ch3/3.37.md: -------------------------------------------------------------------------------- 1 | Since there is no null character at the end, the program will print all the characters in `ca` and continue print whatever in memeory until it find a null character. 2 | -------------------------------------------------------------------------------- /ch3/3.38.md: -------------------------------------------------------------------------------- 1 | The value of a pointer is the address of the object it points. When adding two pointers, the result is sum of two address which means an unknown place in memory. Thus adding two pointers are meaningless. 2 | -------------------------------------------------------------------------------- /ch3/3.39.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::string s1, s2; 6 | std::cin >> s1 >> s2; 7 | if (s1 == s2) 8 | std::cout << "Two strings are equal." << std::endl; 9 | else 10 | std::cout << "Two strings are not equal." << std::endl; 11 | 12 | char cs1[100]; 13 | char cs2[100]; 14 | std::cin >> cs1 >> cs2; 15 | if (!strcmp(cs1, cs2)) 16 | std::cout << "Two C-style strings are equal." << std::endl; 17 | else 18 | std::cout << "Two C-style strings are not equal." << std::endl; 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /ch3/3.40.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | char s1[] = "Hello"; 5 | char s2[] = "World"; 6 | char s3[11]; 7 | strcpy(s3, s1); 8 | strcat(s3, s2); 9 | std::cout << s3 << std::endl; 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /ch3/3.41.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | int ia[] = {1, 2, 3, 4, 5, 6, 7, 8}; 7 | std::vector iv(std::begin(ia), std::end(ia)); 8 | for (const auto &i : iv) 9 | std::cout << i << ' '; 10 | std::cout << std::endl; 11 | 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /ch3/3.42.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::vector iv = {1, 2, 3, 4, 5, 6, 7, 8}; 7 | int ia[10]; 8 | int *bg = ia; 9 | int *ed = ia + iv.size(); 10 | for (const auto &i : iv) 11 | *bg++ = i; 12 | 13 | for (bg = ia; bg != ed; ++bg) 14 | std::cout << *bg << ' '; 15 | std::cout << std::endl; 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /ch3/3.5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void concatenate() { 5 | std::string total, s; 6 | while (std::cin >> s) 7 | total += s; 8 | std::cout << total; 9 | } 10 | 11 | void concatenate_with_space() { 12 | std::string total, s; 13 | if (std::cin >> total) { 14 | while (std::cin >> s) 15 | total += ' ' + s; 16 | } 17 | std::cout << total; 18 | } 19 | 20 | int main() { 21 | //concatenate(); 22 | //concatenate_with_space(); 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /ch3/3.5.in: -------------------------------------------------------------------------------- 1 | aiuf b2 2 | dkjf o32 84 fd 3 | 23 238 8o2 4 | 5 | 6 | fe22 7 | 2984 fdlkj 8 | df 9 | fweflj l2 ldwf 209e 3 10 | -------------------------------------------------------------------------------- /ch3/3.6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::string s; 6 | if (std::cin >> s) { 7 | for (auto &c : s) // `c` is `char &` 8 | c = 'X'; 9 | } 10 | std::cout << s << std::endl; 11 | 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /ch3/3.7.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::string s; 6 | if (std::cin >> s) { 7 | for (char c : s) 8 | c = 'X'; // will not change s 9 | } 10 | std::cout << s << std::endl; 11 | 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /ch3/3.8.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void change_with_while() { 5 | std::string s; 6 | if (std::cin >> s) { 7 | std::string::size_type pos = 0; // also `decltype(s.size()) pos = 0` 8 | while (pos != s.size()) 9 | s[pos++] = 'X'; 10 | } 11 | std::cout << s << std::endl; 12 | } 13 | 14 | void change_with_for() { 15 | std::string s; 16 | if (std::cin >> s) { 17 | for (std::string::size_type pos = 0; pos != s.size(); ++pos) 18 | s[pos] = 'X'; 19 | } 20 | std::cout << s << std::endl; 21 | } 22 | 23 | int main() { 24 | //change_with_while(); 25 | //change_with_for(); 26 | 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /ch3/3.9.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::string s; 6 | std::cout << s[0] << std::endl; // The subscript is out of range, result is undefined. 7 | 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /ch4/4.1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | std::cout << (5 + 10 * 20 / 2) << std::endl; // 105 5 | 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /ch4/4.10.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int i; 5 | while (std::cin >> i && i != 42) { /* do something */ } 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /ch4/4.11.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int a, b, c, d; 5 | std::cin >> a >> b >> c >> d; 6 | if (a > b && b > c && c > d) { /* do something */ } 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /ch4/4.12.md: -------------------------------------------------------------------------------- 1 | The expression `i != j < k` is the same with `i != (j < k)`. 2 | 3 | First, `j < k` is evaluated and the result is a `bool`(either `true` or `false`). 4 | 5 | Second, `i != true` or `i != false` is evaluated. Since `i` is an `int`, the `bool` will be converted to `int`, which means `i != 1` or `i != 0` is evaluated. 6 | -------------------------------------------------------------------------------- /ch4/4.13.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int i; 5 | double d; 6 | d = i = 3.5; 7 | std::cout << d << ' ' << i << std::endl; // 3 3 8 | i = d = 3.5; 9 | std::cout << d << ' ' << i << std::endl; // 3.5 3 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /ch4/4.14.md: -------------------------------------------------------------------------------- 1 | `if (42 = i) // ...` is an error. 2 | 3 | `if (i = 42) // ...` will first assign 42 to `i` and yield the value of `i` as the condition expression of `if` statement. And because 42 is nonzero, the condition will be `true`. 4 | -------------------------------------------------------------------------------- /ch4/4.15.cpp: -------------------------------------------------------------------------------- 1 | int main() { 2 | double dval; 3 | int ival; 4 | int *pi; 5 | //dval = ival = pi = 0; 6 | // the type of `pi` is `int *` which cannot be converted to `int` 7 | dval = ival = 0; 8 | pi = 0; 9 | 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /ch4/4.16.md: -------------------------------------------------------------------------------- 1 | `if (p = getPtr() != 0)` is the same with `if (p = (getPtr() != 0))` and should be `if ((p = getPtr()) != 0)`. 2 | 3 | `if (i = 1024)` may be `if (i == 1024)`. 4 | -------------------------------------------------------------------------------- /ch4/4.17.md: -------------------------------------------------------------------------------- 1 | The prefix increment operator increases the operand and return the operand itself as an lvalue. 2 | 3 | The postfix increment operator increases the operand and return a copy of the operand's original value as an rvalue. 4 | -------------------------------------------------------------------------------- /ch4/4.18.md: -------------------------------------------------------------------------------- 1 | The loop will print all elements except the first one in the vector, and also try to dereference to one past the last element, which is an error. Also, if there is no negative value in the vector, the loop will continue to dereference whatever in memeory until a negative value is found, which is a disaster. 2 | -------------------------------------------------------------------------------- /ch4/4.2.md: -------------------------------------------------------------------------------- 1 | (a) `* vec.begin() ==> * ((vec.begin)())` 2 | 3 | The order is: member selector, function call, dereference. 4 | 5 | (b) `* vec.begin() + 1 ==> ( * ((vec.begin)())) + 1` 6 | 7 | The order is: member selector, function call, dereference, add. 8 | -------------------------------------------------------------------------------- /ch4/4.21.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::vector iv; 6 | int i; 7 | while (std::cin >> i) 8 | iv.push_back(i); 9 | for (auto &elem : iv) 10 | elem = elem % 2 ? elem + elem : elem; 11 | for (const auto &elem : iv) 12 | std::cout << elem << ' '; 13 | std::cout << std::endl; 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /ch4/4.23.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using std::string; 3 | 4 | int main() { 5 | string s = "word"; 6 | //string pl = s + s[s.size() - 1] == 's' ? "" : "s"; 7 | string pl = s + (s[s.size() - 1] == 's' ? "" : "s"); 8 | 9 | // The precedence of the conditional operator is lower than arithmetic operator. 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /ch4/4.24.md: -------------------------------------------------------------------------------- 1 | If the operator were left associative, then the expression 2 | 3 | grade > 90 ? "high pass" 4 | : grade < 60 ? "fail" : "pass"; 5 | 6 | would be evaluated as: 7 | 8 | (grade > 90 ? "high pass" : grade < 60) ? "fail" : "pass"; 9 | 10 | which means: 11 | 12 | - if the grade is greater than 90, then return "high pass", which is not empty string and evaluate to `true`, then return "fail"; 13 | - else evaluates `grade < 60` and takes the result as the condition for the second conditional operator, which means if the grade is less than 60, return "fail", else return "pass". 14 | -------------------------------------------------------------------------------- /ch4/4.25.md: -------------------------------------------------------------------------------- 1 | `~'q' << 6` is the same as `(~'q') << 6`. 2 | 3 | 1. The operand of `~` operator is a "small integer"(`char` here), thus its value is first promoted to a larger integral type(`int` here). 4 | 5 | 'q' = 01110001 promoted to 6 | 00000000 00000000 00000000 01110001 7 | 8 | 2. After the `~` operator evaluated, 9 | 10 | ~'q' 11111111 11111111 11111111 10001110 11 | 12 | 3. Left shift, 13 | 14 | ~'q' << 6 11111111 11111111 11100011 10000000 15 | 16 | 4. The result is -7296. 17 | -------------------------------------------------------------------------------- /ch4/4.26.md: -------------------------------------------------------------------------------- 1 | The standard guarantees the minimum size of `int` is 16 bits, and the minimum size of `long` is 32 bits. Since the teacher has 30 students in a class, which needs at least 30 bits, `int` would be not enough to hold all the results. 2 | -------------------------------------------------------------------------------- /ch4/4.27.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | unsigned long ul1 = 3, ul2 = 7; 5 | 6 | std::cout << (ul1 & ul2) << std::endl; // 3 7 | std::cout << (ul1 | ul2) << std::endl; // 7 8 | std::cout << (ul1 && ul2) << std::endl; // 1, means true 9 | std::cout << (ul1 || ul2) << std::endl; // 1, means true 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /ch4/4.29.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int x[10]; 5 | int *p = x; 6 | std::cout << sizeof(x) / sizeof(*x) << std::endl; // 10 7 | std::cout << sizeof(p) / sizeof(*p) << std::endl; // the size of a pointer / the size of an int 8 | 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /ch4/4.3.md: -------------------------------------------------------------------------------- 1 | I think that is an acceptable trade-off. When an expression refers to and change the same object, we can always seperate that expression into several expressions to avoid the situation except where: 2 | - The operator involved is one of _and `&&`, or `||`, conditional `?:`, comma `,`_ operator, 3 | - The subexpression that change the operand is itself the operand of another subexpression. 4 | -------------------------------------------------------------------------------- /ch4/4.30.md: -------------------------------------------------------------------------------- 1 | (a) `sizeof(x) + y` 2 | (b) `sizeof(p->mem[i])` 3 | (c) `sizeof(a) < b` 4 | (d) `sizeof(f())` 5 | -------------------------------------------------------------------------------- /ch4/4.33.md: -------------------------------------------------------------------------------- 1 | The expression 2 | 3 | sameValue ? ++x, ++y : --x, --y 4 | 5 | is the same as 6 | 7 | (sameValue ? (++x, ++y) : --x), --y 8 | 9 | Then it will be easy to notice that whatever `sameValue` evaluated, `--y` will always be evaluated. 10 | -------------------------------------------------------------------------------- /ch4/4.34.md: -------------------------------------------------------------------------------- 1 | (a) `fval` is converted to `bool`. 2 | (b) `ival` is converted to `float`, then added to `fval`, finally the result is converted to `double`. 3 | (c) `cval` is promoted to `int`, then multiplied by `ival`, then the result is converted to `double`, then added to `dval`. 4 | -------------------------------------------------------------------------------- /ch4/4.36.cpp: -------------------------------------------------------------------------------- 1 | int main() { 2 | int i = 0; 3 | double d = 0; 4 | i *= static_cast(d); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /ch4/4.37.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int i = 0; 5 | double d = 0; 6 | std::string str("some string"); 7 | const std::string *ps = &str; 8 | char c = 'c'; 9 | char *pc = &c; 10 | void *pv; 11 | 12 | //pv = (void*)ps; 13 | pv = static_cast(const_cast(ps)); 14 | //pv = const_cast(ps); // Also work. 15 | 16 | //i = int(*pc); 17 | i = static_cast(*pc); 18 | 19 | //pv = &d; 20 | pv = static_cast(&d); 21 | 22 | //pc = (char*) pv; 23 | pc = static_cast(pv); 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /ch4/4.38.md: -------------------------------------------------------------------------------- 1 | The expression first did integral division `j / i`, then converted the result to `double` and assigned it to `slope`. The result is the same as `double slope = j / i;`. 2 | -------------------------------------------------------------------------------- /ch4/4.4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | // (((12 / 3) * 4) + (5 * 15)) + ((24 % 4) / 2) = 91 5 | std::cout << 12 / 3 * 4 + 5 * 15 + 24 % 4 / 2 << std::endl; 6 | 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /ch4/4.5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | std::cout << -30 * 3 + 21 / 5 << std::endl; // -86 5 | std::cout << -30 + 3 * 21 / 5 << std::endl; // -18 6 | std::cout << 30 / 3 * 21 % 5 << std::endl; // 0 7 | std::cout << -30 / 3 * 21 % 4 << std::endl; // -2 8 | 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /ch4/4.6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int i; 5 | std::cin >> i; 6 | if (i % 2) 7 | std::cout << i << " is an odd number." << std::endl; 8 | else 9 | std::cout << i << " is an even number." << std::endl; 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /ch4/4.8.md: -------------------------------------------------------------------------------- 1 | The logical `AND` and `OR` operators follow the _short-circuit evaluation_ strategy. Which means: 2 | - they always evaluate their left operand before the right, 3 | - the right operand is evaluated _if and only if_ the left operand does not determine the result. 4 | 5 | The equality operator evaluates both the left operand and the right operand, then compares those values. The order of evaluation of the two operands is undefined. 6 | -------------------------------------------------------------------------------- /ch4/4.9.md: -------------------------------------------------------------------------------- 1 | The condition `cp && *cp` means if `cp` is not a null pointer and the object pointed by `cp` is not null, 0 or can be converted to false. 2 | -------------------------------------------------------------------------------- /ch5/5.1.md: -------------------------------------------------------------------------------- 1 | A single `;`(semicolon) is a null statement. It is used where the language requires a statement but the program's logic does not. 2 | -------------------------------------------------------------------------------- /ch5/5.15.md: -------------------------------------------------------------------------------- 1 | (a) 2 | 3 | int ix; 4 | for (ix = 0; ix != sz; ++ix) { /* ... */ } 5 | //for (int ix = 0; ix != sz; ++ix) { /* ... */ } 6 | // The loop variable is used outside `for` scope, thus should be defined outside. 7 | if (ix != sz) 8 | // ... 9 | 10 | (b) 11 | 12 | int ix; 13 | //for (ix != sz; ++ix) { /* ... */ } 14 | // When the initialization is unnecessary, a null statement should be used. 15 | for (; ix != sz; ++ix) { /* ... */ } 16 | 17 | (c) 18 | 19 | for (int ix = 0; ix != sz; ++ix, ++ sz) { /* ... */ } 20 | // The loop will never end. 21 | for (int ix = 0; ix != sz; ++ix) { /* ... */ } 22 | -------------------------------------------------------------------------------- /ch5/5.16.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | int i; 6 | while (std::cin >> i) { /* ... */ } 7 | for (int j; std::cin >> j;) { /* ... */ } 8 | 9 | std::vector iv(10, 1); 10 | for (auto it = iv.begin(); it != iv.end(); ++it) { /* ... */ } 11 | auto it2 = iv.begin(); 12 | while (it2 != iv.end()) { 13 | ++it2; 14 | /* ... */ 15 | } 16 | 17 | // I would choose `for`-loop, because it can do what a `while`-loop can, but 18 | // not vise versa. 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /ch5/5.18.md: -------------------------------------------------------------------------------- 1 | (a) 2 | 3 | //do // Need a block here. 4 | do { 5 | int v1, v2; 6 | cout << "Please enter two numbers to sum:" ; 7 | if (cin >> v1 >> v2) 8 | cout << "Sum is: " << v1 + v2 << endl; 9 | //while (cin); 10 | } while (cin); 11 | 12 | (b) 13 | 14 | int ival; 15 | do { 16 | // ... 17 | //} while (int ival = get_response()); // Error: declaration in a do condition 18 | } while (ival = get_response()); 19 | 20 | (c) 21 | 22 | int ival; 23 | do { 24 | //int ival = get_response(); // Loop will define a new condition variable everytime 25 | ival = get_response(); 26 | } while (ival); 27 | 28 | -------------------------------------------------------------------------------- /ch5/5.19.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::string s1, s2; 6 | std::cin >> s1 >> s2; 7 | do { 8 | std::cout << ( s1 == s2 ? "Equal" 9 | : s1 < s2 ? "First small" : "Second small") 10 | << std::endl; 11 | } while (std::cin >> s1 >> s2); 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /ch5/5.2.md: -------------------------------------------------------------------------------- 1 | A block (also called compound statment) is a (possibily empty) sequence of statements and declarations surrounded by a pair of cruly braces. It is used where the language requires a single statement but the program's logic needs more than one. 2 | -------------------------------------------------------------------------------- /ch5/5.20.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::string last, curr; 6 | bool hasRepeat = false; 7 | while (std::cin >> curr) 8 | if (curr == last) { 9 | std::cout << "Find repeated word: " << curr << std::endl; 10 | hasRepeat = true; 11 | break; 12 | } else { 13 | last = curr; 14 | } 15 | if (!hasRepeat) 16 | std::cout << "No word was repeated." << std::endl; 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /ch5/5.21.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::string last, curr; 6 | bool hasRepeat = false; 7 | while (std::cin >> curr) { 8 | if (curr[0] < 'A' || curr[0] > 'Z') { 9 | last = curr; 10 | continue; 11 | } 12 | if (curr == last) { 13 | std::cout << "Find repeated word: " << curr << std::endl; 14 | hasRepeat = true; 15 | break; 16 | } 17 | last = curr; 18 | } 19 | if (!hasRepeat) 20 | std::cout << "No word was repeated." << std::endl; 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /ch5/5.22.md: -------------------------------------------------------------------------------- 1 | We can use a loop statement to rewrite the code. 2 | 3 | int sz; 4 | while ((sz = get_size()) <= 0) ; // Null statement 5 | 6 | -------------------------------------------------------------------------------- /ch5/5.23.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int a, b; 5 | std::cin >> a >> b; 6 | std::cout << a / b << std::endl; 7 | 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /ch5/5.24.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | int a, b; 6 | std::cin >> a >> b; 7 | if (b == 0) 8 | throw std::runtime_error("Divide by 0."); 9 | std::cout << a / b << std::endl; 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /ch5/5.25.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | int a, b; 6 | bool tryAgain; 7 | do { 8 | tryAgain = false; 9 | try { 10 | std::cin >> a >> b; 11 | if (b == 0) 12 | throw std::runtime_error("Divide by 0."); 13 | std::cout << a / b << std::endl; 14 | } catch (std::runtime_error err) { 15 | std::cout << err.what() << "\nTry again? (y/n)" << std::endl; 16 | char c; 17 | if (std::cin >> c && (c == 'y' || c == 'Y')) 18 | tryAgain = true; 19 | } 20 | } while (tryAgain); 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /ch5/5.3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int sum = 0, val = 1; 5 | //while (val <= 10 && (sum += val++)) ; // null statement 6 | while (val <= 10 && (sum += val, ++val)) ; // null statement 7 | std::cout << "Sum of 1 to 10 inclusive is " << sum << std::endl; 8 | 9 | // I think this rewrite diminishes the readability of the code. 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /ch5/5.4.md: -------------------------------------------------------------------------------- 1 | (a) The loop variable `iter` did not initialized before used. It should be initialized first. 2 | 3 | string::iterator iter = s.begin(); 4 | while (iter != s.end()) { /* ... */ } 5 | 6 | (b) The loop variable `status` is used outside the scope of the `while` statement, thus it should be defined outside that scope. 7 | 8 | bool status; 9 | while (status = find(word)) { /* ... */ } 10 | if (!status) { /* ... */ } 11 | -------------------------------------------------------------------------------- /ch5/5.5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | const std::vector scores = { "F", "D", "C", "B", "A", "A++"}; 7 | std::string lettergrade; 8 | int grade; 9 | std::cin >> grade; 10 | if (grade >= 60) 11 | lettergrade = scores[(grade - 50) / 10]; 12 | else 13 | lettergrade = scores[0]; 14 | std::cout << lettergrade << std::endl; 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /ch5/5.6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | const std::vector scores = { "F", "D", "C", "B", "A", "A++"}; 7 | std::string lettergrade; 8 | int grade; 9 | std::cin >> grade; 10 | lettergrade = grade < 60 ? scores[0] : scores[(grade - 50) / 10]; 11 | std::cout << lettergrade << std::endl; 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /ch5/5.7.md: -------------------------------------------------------------------------------- 1 | (a) 2 | 3 | if (ival1 != ival2) 4 | ival1 = ival2; // Missing semicolon 5 | else ival1 = ival2 = 0; 6 | 7 | (b) 8 | 9 | if (ival < minval) { // Need a block for more than one statements 10 | minval = ival; 11 | occurs = 1; 12 | } 13 | 14 | (c) 15 | 16 | int ival; // Used outside the first if scope, thus defined outside 17 | if (ival = get_value()) 18 | cout << "ival = " << ival << endl; 19 | if (!ival) 20 | cout << "ival = 0\n"; 21 | 22 | (d) 23 | 24 | if (ival == 0) // Should be equality operator instead of assignment 25 | ival = get_value(); 26 | -------------------------------------------------------------------------------- /ch5/5.8.md: -------------------------------------------------------------------------------- 1 | A "dangling `else`" means the ambiguity that an `else` may belong to several `if`. In C++, this is resolved by specifying that each `else` is matched with the closest preceding unmatched `if`. 2 | -------------------------------------------------------------------------------- /ch6/6.1.md: -------------------------------------------------------------------------------- 1 | A **parameter** is the variable in the parentheses after the function name when we defining the function and used inside a function. 2 | 3 | An **argument** is the variable in the parentheses after the function name when we calling the function, and it is used to initialize the parameter of the function. 4 | -------------------------------------------------------------------------------- /ch6/6.10.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void swapInt(int *a, int *b) { 4 | int tmp = *a; 5 | *a = *b; 6 | *b = tmp; 7 | } 8 | 9 | int main() { 10 | int a, b; 11 | std::cin >> a >> b; 12 | swapInt(&a, &b); 13 | std::cout << a << " " << b << std::endl; 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /ch6/6.11.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void resetInt(int &i) { 4 | i = 0; 5 | } 6 | 7 | int main() { 8 | int a; 9 | std::cin >> a; 10 | std::cout << "before reset: " << a << std::endl; 11 | resetInt(a); 12 | std::cout << "after reset: " << a << std::endl; 13 | 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /ch6/6.12.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void swapInt(int &a, int &b) { 4 | int tmp = a; 5 | a = b; 6 | b = tmp; 7 | } 8 | 9 | int main() { 10 | int a, b; 11 | std::cin >> a >> b; 12 | swapInt(a, b); 13 | std::cout << a << " " << b << std::endl; 14 | 15 | // The reference version looks like easier to use, but the user must know 16 | // from other source that the function will change the value of the argument. 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /ch6/6.13.md: -------------------------------------------------------------------------------- 1 | `void f(T)` will pass the argument by value, which means in the function `f`, a copy of `T` will be made. 2 | 3 | `void f(T&)` will pass the argument by reference, which means in the function `f`, the same variable defined in the caller is used. 4 | -------------------------------------------------------------------------------- /ch6/6.16.md: -------------------------------------------------------------------------------- 1 | The parameter of the function should be `const string &s`. So that we can pass string literals or const strings to the function. 2 | -------------------------------------------------------------------------------- /ch6/6.18.md: -------------------------------------------------------------------------------- 1 | (a) 2 | 3 | bool compare(const matrix &, const matrix &); 4 | 5 | (b) 6 | 7 | vector::iterator &change_val(int, vector::iterator &); 8 | 9 | -------------------------------------------------------------------------------- /ch6/6.19.md: -------------------------------------------------------------------------------- 1 | (a) Illegal. Only one parameter is needed for the function. 2 | (b) Legal. 3 | (c) Legal. 4 | (d) Legal. 5 | -------------------------------------------------------------------------------- /ch6/6.2.md: -------------------------------------------------------------------------------- 1 | (a) 2 | 3 | //int f() { // Return type doesn't match 4 | string f() { 5 | string s; 6 | // ... 7 | return s; 8 | } 9 | 10 | (b) 11 | 12 | //f2(int i) { /* ... */ } // Must have a return type 13 | void f2(int i) { /* ... */ } 14 | 15 | (c) 16 | 17 | //int calc(int v1, int v1) /* ... */ } // Forget begin brace `{`, and no two paramaters can have the same name. 18 | int calc(int v1, int v2) { /* ... */ } 19 | 20 | (d) 21 | 22 | //double square(double x) return x * x; // The function body should be a block. 23 | double square(double x) { return x * x; } 24 | 25 | 26 | -------------------------------------------------------------------------------- /ch6/6.20.md: -------------------------------------------------------------------------------- 1 | If the reference parameters will not be changed inside function, then they should be reference to `const`. 2 | 3 | If we make a parameter a plain reference, then we can not pass 4 | - a `const` object, 5 | - or a literal, 6 | - or an object that requires conversion 7 | to a plain reference parameter. 8 | -------------------------------------------------------------------------------- /ch6/6.21.cpp: -------------------------------------------------------------------------------- 1 | int largerInt(int a, int *pb) { 2 | return a > *pb ? a : *pb; 3 | } 4 | -------------------------------------------------------------------------------- /ch6/6.24.md: -------------------------------------------------------------------------------- 1 | The function prototype is the same as `void print(const int *ia)`, which means we can pass any pointer to int to the function, not only an array of ten `int`s. This will lead to an error. We can change the parameter to a reference to array: 2 | 3 | void print(const int (&ia)[10]) { /* ... */ } 4 | 5 | -------------------------------------------------------------------------------- /ch6/6.25.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char *argv[]) { 5 | std::cout << "All " << argc << " argument" 6 | << (argc > 1 ? "s are:" : " is:") << std::endl; 7 | for (int i = 0; i < argc; ++i) 8 | std::cout << i << "\t" << argv[i] << std::endl; 9 | if (argc < 3) // programname argument1 argument2 0 10 | return -1; 11 | std::string args(argv[1]); 12 | args += argv[2]; 13 | std::cout << args << std::endl; 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /ch6/6.26.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char *argv[]) { 5 | std::cout << "All " << argc << " argument" 6 | << (argc > 1 ? "s are:" : " is:") << std::endl; 7 | for (int i = 0; i < argc; ++i) 8 | std::cout << i << "\t" << argv[i] << std::endl; 9 | 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /ch6/6.27.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int sumIntList(std::initializer_list il) { 5 | int sum = 0; 6 | // `il.begin()` or `il.end()` will return `const int *` 7 | for (auto &e : il) // `e` is `const int &`, since element in `il` are `const int` 8 | sum += e; 9 | return sum; 10 | } 11 | 12 | int main() { 13 | std::cout << sumIntList({1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) << std::endl; 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /ch6/6.28.md: -------------------------------------------------------------------------------- 1 | The type of `elem` is `const string &`. 2 | -------------------------------------------------------------------------------- /ch6/6.29.md: -------------------------------------------------------------------------------- 1 | Yes, I would use a reference as the loop control variable. So that we don't need to copy the value from the `initializer_list`. 2 | -------------------------------------------------------------------------------- /ch6/6.3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int fact(int n) { // Ignore overflow 4 | if (n < 1) return n; 5 | int k = n; 6 | while (--n) 7 | k *= n; 8 | return k; 9 | } 10 | 11 | int main() { 12 | int n; 13 | std::cin >> n; 14 | std::cout << n << "! = " << fact(n) << std::endl; 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /ch6/6.30.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using std::string; 4 | 5 | bool str_subrange(const string &str1, const string &str2) { 6 | if (str1.size() == str2.size()) 7 | return str1 == str2; 8 | auto size = (str1.size() < str2.size()) ? str1.size() : str2.size(); 9 | for (decltype(size) i = 0; i != size; ++i) { 10 | if (str1[i] != str2[i]) 11 | //return; // Error: need a return value 12 | return false; 13 | } 14 | // Error: need a return statement 15 | return true; 16 | } 17 | 18 | int main() { 19 | string s1, s2; 20 | std::cin >> s1 >> s2; 21 | std::cout << str_subrange(s1, s2) << std::endl; 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /ch6/6.31.md: -------------------------------------------------------------------------------- 1 | When the object is not a local object, then that's fine to return a reference to it. 2 | 3 | When we don't want the reference returned from a function to be an lvalue, we should use a reference to `const` as the return type instead. 4 | -------------------------------------------------------------------------------- /ch6/6.32.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int &get(int *arry, int index) { 4 | return arry[index]; 5 | } 6 | 7 | // The function is legal. It return a reference to the element at `index` in 8 | // array `arry`. The reference return is lvalue, thus can be used to assign to 9 | // the array. 10 | 11 | int main() { 12 | int ia[10]; 13 | for (int i = 0; i != 10; ++i) 14 | get(ia, i) = i; 15 | 16 | for (int i = 0; i != 10; ++i) 17 | std::cout << ia[i] << " "; 18 | std::cout << std::endl; 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /ch6/6.33.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void printVecInt(const std::vector::iterator bg, 5 | const std::vector::iterator ed) { 6 | if (bg == ed) 7 | return; 8 | std::cout << *bg << " "; 9 | printVecInt(bg + 1, ed); 10 | } 11 | 12 | int main() { 13 | std::vector vi; 14 | int i; 15 | while (std::cin >> i) 16 | vi.push_back(i); 17 | 18 | printVecInt(vi.begin(), vi.end()); 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /ch6/6.34.md: -------------------------------------------------------------------------------- 1 | If we pass a negative number to the function, then it will recursively call itself infinitely. 2 | -------------------------------------------------------------------------------- /ch6/6.35.md: -------------------------------------------------------------------------------- 1 | The order of evaluation is undefined for the operator `*`, thus the expression `return factorial(val--) * val` make equal to either of the following expressions: 2 | 3 | // Version 1 4 | auto tmp = factorial(val) * val; // evaluate second operand first 5 | --val; 6 | return tmp; 7 | 8 | // Version 2 9 | auto tmp = factorial(val); 10 | --val; 11 | return tmp * val; // evaluate first operand first 12 | 13 | -------------------------------------------------------------------------------- /ch6/6.36.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using std::string; 3 | 4 | string (&foo1())[10]; 5 | -------------------------------------------------------------------------------- /ch6/6.38.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int odd[] = {1, 3, 5, 7, 9}; 4 | int even[] = {0, 2, 4, 6, 8}; 5 | auto arrPtr(int i) -> int (&)[5] { 6 | return i % 2 ? odd : even; 7 | } 8 | 9 | int main() { 10 | int i; 11 | std::cin >> i; 12 | int (&arr)[5] = arrPtr(i); 13 | int *arr2 = arrPtr(i); 14 | //int arr3[5] = arrPtr(i); // Error 15 | //int (*arr4)[5] = arrPtr(i); // Error 16 | std::cout << arr[0] << " " << arr2[0] << std::endl; 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /ch6/6.39.md: -------------------------------------------------------------------------------- 1 | (a) 2 | 3 | int calc(int, int); 4 | int calc(const int, const int); // Same with first line, top-level `const` are ignored 5 | 6 | (b) 7 | 8 | int get(); 9 | double get(); // Error, differ only on return types 10 | 11 | (c) 12 | 13 | int *reset(int *); 14 | double *reset(double *); // OK, define an overloaded function 15 | 16 | -------------------------------------------------------------------------------- /ch6/6.4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int fact(int n) { // Ignore overflow 4 | if (n < 1) return n; 5 | int k = n; 6 | while (--n) 7 | k *= n; 8 | return k; 9 | } 10 | 11 | int main() { 12 | int n; 13 | while (std::cin >> n) 14 | std::cout << n << "! = " << fact(n) << std::endl; 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /ch6/6.40.md: -------------------------------------------------------------------------------- 1 | (a) 2 | 3 | int ff(int a, int b = 0, int c = 0); // OK 4 | 5 | (b) 6 | 7 | char *init(int ht = 24, int wd, char bckgrnd); 8 | // Error, all the parameters followed `ht` must also have default argument. 9 | 10 | -------------------------------------------------------------------------------- /ch6/6.41.md: -------------------------------------------------------------------------------- 1 | (a) `init();` is illegal, must have at least one argument. 2 | 3 | (b) `init(24, 10);` is legal. 4 | 5 | (c) `init(14, '*');` is legal, but unlikely to match the programer's intent. Because the character `*` will be promoted to `int` and match `wd`. 6 | -------------------------------------------------------------------------------- /ch6/6.42.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | std::string make_plural(size_t ctr, const std::string &word, 5 | const std::string &ending = "s") { 6 | return (ctr > 1) ? word + ending : word; 7 | } 8 | 9 | int main() { 10 | std::cout << "success: " << make_plural(2, "success", "es") << std::endl; 11 | std::cout << "failure: " << make_plural(2, "failure") << std::endl; 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /ch6/6.43.md: -------------------------------------------------------------------------------- 1 | The declarations of both functions should be put in a header. The definition of function `eq` should be put in the same header with declaration. The definition of function `putValues` may be put in a source file. 2 | -------------------------------------------------------------------------------- /ch6/6.44.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | inline bool isShorter(const std::string &s1, const std::string &s2) { 4 | return s1.size() < s2.size(); 5 | } 6 | -------------------------------------------------------------------------------- /ch6/6.45.cpp: -------------------------------------------------------------------------------- 1 | // Bypass 2 | -------------------------------------------------------------------------------- /ch6/6.46.md: -------------------------------------------------------------------------------- 1 | No, a `constexpr` function may only contains statements that generate no actions at run time, but the member method `size()` must be called at run time, thus the function can not be a `constexpr` function. 2 | 3 | 11 | -------------------------------------------------------------------------------- /ch6/6.47.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void printVecInt(const std::vector::iterator bg, 5 | const std::vector::iterator ed) { 6 | #ifndef NDEBUG 7 | std::cout << "In function: " << __func__ << ", " 8 | << "Vector size: " << ed - bg << std::endl; 9 | #endif 10 | if (bg == ed) 11 | return; 12 | std::cout << *bg << std::endl; 13 | printVecInt(bg + 1, ed); 14 | } 15 | 16 | int main() { 17 | std::vector vi; 18 | int i; 19 | while (std::cin >> i) 20 | vi.push_back(i); 21 | 22 | printVecInt(vi.begin(), vi.end()); 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /ch6/6.48.md: -------------------------------------------------------------------------------- 1 | The loop are used to keep reading string from the input until `sought` found. It is a bad idea to use `assert` check whether `cin` is in an error state. Because when the program compiled with `NDEBUG` preprocessor variable, the statement would not be excuted. 2 | -------------------------------------------------------------------------------- /ch6/6.49.md: -------------------------------------------------------------------------------- 1 | A **candidate function** is a function with the same name as the called function and for which a declaration is visible at the point of the call. 2 | 3 | A **viable function** is a candidate function with the same number of parameters as there are arguments in the call, and the type of each argument must match or be convertible to the type of its corresponding parameter. 4 | -------------------------------------------------------------------------------- /ch6/6.5.cpp: -------------------------------------------------------------------------------- 1 | int absInt(int i) { 2 | return i >= 0 ? i : -i; 3 | } 4 | -------------------------------------------------------------------------------- /ch6/6.50.md: -------------------------------------------------------------------------------- 1 | (a) `f(2.56, 42)` is illegal. The call is ambiguous, because either `f(int, int)` or `f(double, double)` is a better match than the other on one of the arguments to the call. 2 | 3 | (b) `f(42)` has a best match function `f(int)`. 4 | (c) `f(42, 0)` has a best match function `f(int, int)`. 5 | (d) `f(2.56, 3.14)` has a best match function `f(double, double)`. 6 | -------------------------------------------------------------------------------- /ch6/6.52.md: -------------------------------------------------------------------------------- 1 | (a) `manip('a', 'z');` rank 3. 2 | (b) `manip(55.4, dobj);` rank 4. 3 | -------------------------------------------------------------------------------- /ch6/6.53.md: -------------------------------------------------------------------------------- 1 | (a) 2 | 3 | int calc(int&, int&); 4 | int calc(const int&, const int&); 5 | // OK, overloaded function takes reference to `const` 6 | 7 | (b) 8 | 9 | int calc(char*, char*); 10 | int calc(const char*, const char*); 11 | // OK, overloaded function takes pointer to `const` 12 | 13 | (c) 14 | 15 | int calc(char*, char*); 16 | int calc(char* const, char* const); 17 | // Error, redeclare the same function, top-level `const` is ignored 18 | 19 | -------------------------------------------------------------------------------- /ch6/6.54.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int foo(int, int); 5 | int bar(int, int); 6 | 7 | int main() { 8 | std::vector vf; 9 | 10 | vf.push_back(foo); 11 | vf.push_back(bar); 12 | 13 | vf[0](1, 2); 14 | vf[1](3, 4); 15 | 16 | for (const auto &e : vf) 17 | e(9, 9); 18 | 19 | return 0; 20 | } 21 | 22 | int foo(int a, int b) { 23 | std::cout << "Called foo(" << a << ", " << b << ")" << std::endl; 24 | return 0; 25 | } 26 | 27 | int bar(int a, int b) { 28 | std::cout << "Called bar(" << a << ", " << b << ")" << std::endl; 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /ch6/6.56.md: -------------------------------------------------------------------------------- 1 | See [ex6.55](6.55.cpp). 2 | -------------------------------------------------------------------------------- /ch6/6.7.cpp: -------------------------------------------------------------------------------- 1 | int foo() { 2 | static int cnt = 0; 3 | return cnt++; 4 | } 5 | -------------------------------------------------------------------------------- /ch6/6.8/Chapter6.h: -------------------------------------------------------------------------------- 1 | // For ex6.8 2 | #ifndef CHAPTER_6_H 3 | #define CHAPTER_6_H 4 | 5 | int fact(int); 6 | int absInt(int); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /ch6/6.9/Chapter6.h: -------------------------------------------------------------------------------- 1 | // For ex6.9 2 | #ifndef CHAPTER_6_H 3 | #define CHAPTER_6_H 4 | 5 | int fact(int); 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /ch6/6.9/fact.cc: -------------------------------------------------------------------------------- 1 | #include "Chapter6.h" 2 | 3 | int fact(int n) { // Ignore overflow 4 | if (n < 1) return n; 5 | int k = n; 6 | while (--n) 7 | k *= n; 8 | return k; 9 | } 10 | -------------------------------------------------------------------------------- /ch6/6.9/factMain.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Chapter6.h" 3 | 4 | int main() { 5 | int n; 6 | while (std::cin >> n) 7 | std::cout << n << "! = " << fact(n) << std::endl; 8 | 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /ch7/7.10.md: -------------------------------------------------------------------------------- 1 | The condition test if both `data1` and `data2` are read correctly. 2 | -------------------------------------------------------------------------------- /ch7/7.16.md: -------------------------------------------------------------------------------- 1 | There is no constraint on where and how often an access specifier may appear inside a class definition. A class may contain zero or more access specifiers, each kind of access specifiers can appears multiple times. There is no constraint on the sequence of access specifiers too. 2 | 3 | The constructors and member functions that are part of the interface should be defined after a `public` specifier. 4 | 5 | The data members and member functions that are part of the implementation should be defined after a `private` specifier. 6 | -------------------------------------------------------------------------------- /ch7/7.17.md: -------------------------------------------------------------------------------- 1 | The only difference between `struct` and `class` is the default access level. The members defined before the first access specifier are `public` in `struct`, while those are `private` in `class`. 2 | -------------------------------------------------------------------------------- /ch7/7.18.md: -------------------------------------------------------------------------------- 1 | Encapsulation enforces the separation between interface and implementation in a class via access specifiers. Encapsulation provides some advantages: 2 | 3 | - A class that is encapsulated hides its implementation to the user of the class, thus the user need not know how the class works, they can regard the class as a type (like a built-in type) instead. 4 | - User code cannot inadvertently corrupt the state of an encapsulated object. 5 | - The implementation of an encapsulated class can change over time without requiring changes in user code. 6 | -------------------------------------------------------------------------------- /ch7/7.2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Sales_data { 5 | std::string isbn() const { return bookNo; } 6 | Sales_data &combine(const Sales_data &); 7 | 8 | std::string bookNo; 9 | unsigned units_sold = 0; 10 | double revenue = 0.0; 11 | }; 12 | 13 | Sales_data &Sales_data::combine(const Sales_data &rhs) { 14 | units_sold += rhs.units_sold; 15 | revenue += rhs.revenue; 16 | return *this; 17 | } 18 | 19 | 20 | int main() { 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /ch7/7.20.md: -------------------------------------------------------------------------------- 1 | A **friend** of a class can access non`public` members of that class. 2 | 3 | Pros: 4 | - For functions that are part of the interface while not a member of the class, they can access the non`public` members of that class. 5 | 6 | Cons: 7 | - If the implementation of the class changes over time, its friend may also requiring changes. 8 | -------------------------------------------------------------------------------- /ch7/7.24.md: -------------------------------------------------------------------------------- 1 | See [ex7.23](7.23.cpp). 2 | -------------------------------------------------------------------------------- /ch7/7.25.md: -------------------------------------------------------------------------------- 1 | Yes, because all the data members of `Screen` are built-in types or `string`, which can rely on synthesized versions for copy and assignment. 2 | -------------------------------------------------------------------------------- /ch7/7.28.md: -------------------------------------------------------------------------------- 1 | If then, every time we call `move`, `set` or `display`, the function will return a new `Screen` object that is the copy of the original `Screen` object with the changes we made, while the original `Screen` object keeps unchanged. 2 | -------------------------------------------------------------------------------- /ch7/7.30.md: -------------------------------------------------------------------------------- 1 | Proc: 2 | - It is much more clear by using `this` to refer members. 3 | - The parameters in member function can have the same name as the data members if we use `this` pointer to refer data members. 4 | 5 | Cons: 6 | - The code will look redundant. 7 | -------------------------------------------------------------------------------- /ch7/7.31.cpp: -------------------------------------------------------------------------------- 1 | struct Y; 2 | 3 | struct X { 4 | Y *y; 5 | }; 6 | 7 | struct Y { 8 | X x; 9 | }; 10 | 11 | int main() { 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /ch7/7.33.md: -------------------------------------------------------------------------------- 1 | The return type `pos` is a member `typedef` of class `Screen`, thus it needs the scope operator `Screen::pos`. 2 | -------------------------------------------------------------------------------- /ch7/7.34.md: -------------------------------------------------------------------------------- 1 | Then every usage of `pos` would be an error because of lacking definition. 2 | -------------------------------------------------------------------------------- /ch7/7.35.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef std::string Type; 4 | 5 | Type initVal(); // std::string 6 | 7 | class Exercise { 8 | public: 9 | typedef double Type; 10 | Type setVal(Type); // double setVal(double) 11 | Type initVal(); // double initVal() 12 | private: 13 | int val; 14 | }; 15 | 16 | Exercise::Type Exercise::setVal(Type parm) { // double Exercise::setVal(double para) 17 | //Type Exercise::setVal(Type parm) { // Error: int Exercise::setVal(double para) 18 | val = parm + initVal(); 19 | return val; 20 | } 21 | 22 | Exercise::Type Exercise::initVal() { 23 | return 0; 24 | } 25 | 26 | int main() { 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /ch7/7.36.md: -------------------------------------------------------------------------------- 1 | The order of member initialization is the same with the order they appear in the class definition. Since `rem` appears first, it will be initialized first. But the value of `base` is undefined when `rem` is initialized, thus the value of `rem` is undefined. To fix the problem, we can either switch the order of definitions of `rem` and `base` or we can use the constructor parameters `i` and `j` direct initialize `rem(i % j)`. 2 | -------------------------------------------------------------------------------- /ch7/7.37.md: -------------------------------------------------------------------------------- 1 | The constructors used are list in comment. 2 | 3 | Sales_data first_item(cin); // Sales_data(std::istream &is); 4 | int main() { 5 | Sales_data next; // Sales_data(std::string s = ""); 6 | Sales_data last("9-999-99999-9"); // Sales_data(std::string s = ""); 7 | } 8 | 9 | -------------------------------------------------------------------------------- /ch7/7.39.md: -------------------------------------------------------------------------------- 1 | It is illegal for both constructors to have default arguments. If then, there will be two default constructors, and that's an error. 2 | -------------------------------------------------------------------------------- /ch7/7.4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Person { 4 | std::string name; 5 | std::string address; 6 | }; 7 | 8 | int main() { 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /ch7/7.43.cpp: -------------------------------------------------------------------------------- 1 | class NoDefault { 2 | public: 3 | NoDefault(int i) : i_(i) {} 4 | private: 5 | int i_; 6 | }; 7 | 8 | class C { 9 | public: 10 | C() : nd(0) {} 11 | 12 | private: 13 | NoDefault nd; 14 | }; 15 | 16 | int main() { 17 | C c; 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /ch7/7.44.md: -------------------------------------------------------------------------------- 1 | It is illegal, the constructor of `vector` taken a single number will call the default constructor of elements to value initialze its elements, but the class of the elements `NoDefault` does not have a default constructor, thus the code will not compile. 2 | -------------------------------------------------------------------------------- /ch7/7.45.md: -------------------------------------------------------------------------------- 1 | Then the code `vector vec(10);` is legal. 2 | -------------------------------------------------------------------------------- /ch7/7.47.md: -------------------------------------------------------------------------------- 1 | It should be `explicit`. Otherwise, code like `item.combine("9-999-99999-9")` will compile, but the code has no logical meaning. 2 | 3 | Making the constructor `explicit` will stop compiler from automatically converting one type to the class type, which makes the code same as anticipation. 4 | 5 | The drawback is we must call the constructor explicitly if we want to cover one type to the class type. 6 | -------------------------------------------------------------------------------- /ch7/7.48.md: -------------------------------------------------------------------------------- 1 | If the constructors are not `explicit`. 2 | 3 | string null_isbn("9-999-99999-9"); // call string ctor 4 | Sales_data item1(null_isbn); // call Sales_data ctor 5 | Sales_data item2("9-999-99999-9"); 6 | // first cover "9-999-99999-9" to string, then call Sales_data ctor 7 | 8 | If the constructors are `explicit`, the same operations happen. 9 | -------------------------------------------------------------------------------- /ch7/7.49.md: -------------------------------------------------------------------------------- 1 | (a) `Sales_data &combine(Sales_data);` The code works correct. It will first convert `s` to `Sales_data`, then copy that temporary into the parameter of `combine`. 2 | 3 | (b) `Sales_data &combine(Sales_data&);` The code is wrong. It will first convert `s` to `Sales_data`, then pass the reference to that temporary into the parameter of `combine`, but passing a reference to a temporary is error. 4 | 5 | (c) `Sales_data &combine(const Sales_data&) const;` The code could not compile, because it should not be a const member function. It will first convert `s` to `Sales_data`, then pass the const reference to that temporary into the parameter of `combine`. 6 | -------------------------------------------------------------------------------- /ch7/7.5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Person { 4 | std::string getName() const { return name; } 5 | std::string getAddress() const { return address; } 6 | 7 | std::string name; 8 | std::string address; 9 | }; 10 | 11 | // The member function `getName` and `getAddress` should be `const`, because 12 | // they don't change the object. 13 | 14 | int main() { 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /ch7/7.51.md: -------------------------------------------------------------------------------- 1 | Because semantically speaking, a number is different from a vector, but a char array is the same as a string. 2 | -------------------------------------------------------------------------------- /ch7/7.52.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Sales_data { 4 | std::string bookNo; 5 | unsigned units_sold; //= 0; 6 | double revenue; //= 0.0; 7 | // Error: Cannot provide in-class initializer for an aggregate class 8 | // (since C++11) (until C++14) 9 | }; 10 | 11 | int main() { 12 | Sales_data item = {"978-0590353403", 25, 15.99}; 13 | 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /ch7/7.54.md: -------------------------------------------------------------------------------- 1 | No, because the function cotains excutable statement other than `return`. 2 | -------------------------------------------------------------------------------- /ch7/7.55.md: -------------------------------------------------------------------------------- 1 | No, because `std::string` is not a literal type. 2 | -------------------------------------------------------------------------------- /ch7/7.56.md: -------------------------------------------------------------------------------- 1 | A `static` class member is a member that is associated with the class, rather than with individual objects of the class type. It exists outside any object of the class. 2 | 3 | Advantages: 4 | 5 | - Storage efficient. 6 | - If a `static` member of a class changes, each object of the class will use the new value of that `static` member. 7 | - A `static` data member can have incomplete type. 8 | - A `static` member (either a data member or a member function) can be used as a default argument. 9 | 10 | Differences between ordinary members and `static` members: 11 | 12 | - A `static` member belongs to the class, an ordinary member belongs to objects of the class. 13 | -------------------------------------------------------------------------------- /ch7/7.58.md: -------------------------------------------------------------------------------- 1 | // example.h 2 | class Example { 3 | public: 4 | static double rate; // = 6.5; 5 | // static member should be initialize ouside class 6 | static const int vecSize = 20; 7 | static vector vec; //(vecSize); 8 | // 1. cannot use parentheses as in-class initializer 9 | // 2. static member should be initialize ouside class 10 | }; 11 | 12 | // example.C 13 | #include "example.h" 14 | double Example::rate = 6.5; 15 | // should initialize static data member 16 | vector Example::vec(vecSize); 17 | // should initialize static data member 18 | 19 | -------------------------------------------------------------------------------- /ch7/7.8.md: -------------------------------------------------------------------------------- 1 | The `read` function will change its `Sales_data` parameter and pass the information back via plain reference. 2 | 3 | The `print` function won't change its `Sales_data` parameter, and by using a reference to `const`, we can print `const Sales_data` object as well. 4 | -------------------------------------------------------------------------------- /ch7/7.9.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Person { 5 | std::string getName() const { return name; } 6 | std::string getAddress() const { return address; } 7 | 8 | std::string name; 9 | std::string address; 10 | }; 11 | 12 | std::istream &read(std::istream &is, Person &rhs) { 13 | is >> rhs.name >> rhs.address; 14 | return is; 15 | } 16 | 17 | std::ostream &print(std::ostream &os, const Person &rhs) { 18 | os << rhs.getName() << " " << rhs.getAddress(); 19 | return os; 20 | } 21 | 22 | int main() { 23 | Person p1; 24 | read(std::cin, p1); 25 | print(std::cout, p1) << std::endl; 26 | 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /ch8/8.1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | std::istream &read(std::istream &is) { 5 | //auto old_state = is.rdstate(); 6 | is.clear(); 7 | std::string str; 8 | while (is >> str) 9 | std::cout << str << " "; 10 | std::cout << std::endl; 11 | is.clear(); 12 | //is.setstate(old_state); 13 | return is; 14 | } 15 | 16 | int main() { 17 | read(std::cin); 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /ch8/8.10.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | std::vector vs; 9 | std::string filename; 10 | std::cin >> filename; 11 | std::ifstream in(filename); 12 | if (!in) { 13 | std::cerr << "Fail to open file: " << filename << std::endl; 14 | return -1; 15 | } 16 | for (std::string line; std::getline(in, line); vs.push_back(line)) {} 17 | for (const auto &e : vs) { 18 | std::istringstream iss(e); 19 | for (std::string word; iss >> word; std::cout << word << std::endl) {} 20 | } 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /ch8/8.12.md: -------------------------------------------------------------------------------- 1 | Because the synthesised default constructor will be called when an object of class `PersonInfo` is created, which will default initialized its data members. Meanwhile, both `string` and `vector` have default constructors, and will be used when default initialized. Thus, we don't need in-class initializers to initialze data members in `PersonInfo`. 2 | -------------------------------------------------------------------------------- /ch8/8.13.in: -------------------------------------------------------------------------------- 1 | ZhangSan 13011112222 12345678901 2 | LiSi 13133334444 3 | WangWu 13255556666 12345678901 12345678901 4 | ZhaoLiu 12345678 5 | Lucy 99988887777 12345678901 6 | Lily 99988887777 123456 12345678901 7 | Smith something 8 | Peter 22233331111 9 | -------------------------------------------------------------------------------- /ch8/8.14.md: -------------------------------------------------------------------------------- 1 | By using reference, we avoid copy every object in vectors. By using `const`, we avoid accidentally changing the values of elements in vectors. 2 | -------------------------------------------------------------------------------- /ch8/8.2.md: -------------------------------------------------------------------------------- 1 | See [ex8.1](8.1.cpp). 2 | -------------------------------------------------------------------------------- /ch8/8.3.md: -------------------------------------------------------------------------------- 1 | The condition of a stream is equivalent to `!fail()`, which means set either `failbit` or `badbit` will terminate the loop. For example, errors list below will terminate the loop: 2 | 3 | - System-level failure. (Set the `badbit`) Such as an unrecoverable r/w error. 4 | - Recoverable error. (Set the `failbit`) Such as reading a character when numeric data expected. 5 | - Reaching end-of-file. (Set both the `eofbit` and `failbit`) 6 | -------------------------------------------------------------------------------- /ch8/8.6.in: -------------------------------------------------------------------------------- 1 | 0-201-12345-X 3 20.00 2 | 0-201-12345-X 2 20.00 3 | 0-201-12345-X 3 20.00 4 | 0-201-12345-X 4 20.00 5 | 0-201-12345-X 2 21.50 6 | 0-201-12345-X 2 25.50 7 | 0-201-12345-X 4 10.00 8 | 0-201-12345-X 1 40.00 9 | 0-201-12345-X 6 8.00 10 | 0-201-12345-X 2 25.50 11 | 0-201-12345-X 0 20.00 12 | 0-202-12345-X 2 25.50 13 | 0-202-12345-X 2 25.50 14 | 0-203-12345-X 4 10.00 15 | 0-203-12345-X 4 10.00 16 | 0-203-12345-X 5 13.00 17 | 0-204-12345-X 1 40.00 18 | 0-205-12345-X 6 2.00 19 | 0-205-12345-X 6 3.50 20 | 0-205-12345-X 3 4.00 21 | 0-205-12345-X 5 3.00 22 | 0-206-12345-X 3 24.00 23 | -------------------------------------------------------------------------------- /ch8/8.7.in: -------------------------------------------------------------------------------- 1 | 0-201-12345-X 3 20.00 2 | 0-201-12345-X 2 20.00 3 | 0-201-12345-X 3 20.00 4 | 0-201-12345-X 4 20.00 5 | 0-201-12345-X 2 21.50 6 | 0-201-12345-X 2 25.50 7 | 0-201-12345-X 4 10.00 8 | 0-201-12345-X 1 40.00 9 | 0-201-12345-X 6 8.00 10 | 0-201-12345-X 2 25.50 11 | 0-201-12345-X 0 20.00 12 | 0-202-12345-X 2 25.50 13 | 0-202-12345-X 2 25.50 14 | 0-203-12345-X 4 10.00 15 | 0-203-12345-X 4 10.00 16 | 0-203-12345-X 5 13.00 17 | 0-204-12345-X 1 40.00 18 | 0-205-12345-X 6 2.00 19 | 0-205-12345-X 6 3.50 20 | 0-205-12345-X 3 4.00 21 | 0-205-12345-X 5 3.00 22 | 0-206-12345-X 3 24.00 23 | -------------------------------------------------------------------------------- /ch8/8.8.in: -------------------------------------------------------------------------------- 1 | 0-201-12345-X 3 20.00 2 | 0-201-12345-X 2 20.00 3 | 0-201-12345-X 3 20.00 4 | 0-201-12345-X 4 20.00 5 | 0-201-12345-X 2 21.50 6 | 0-201-12345-X 2 25.50 7 | 0-201-12345-X 4 10.00 8 | 0-201-12345-X 1 40.00 9 | 0-201-12345-X 6 8.00 10 | 0-201-12345-X 2 25.50 11 | 0-201-12345-X 0 20.00 12 | 0-202-12345-X 2 25.50 13 | 0-202-12345-X 2 25.50 14 | 0-203-12345-X 4 10.00 15 | 0-203-12345-X 4 10.00 16 | 0-203-12345-X 5 13.00 17 | 0-204-12345-X 1 40.00 18 | 0-205-12345-X 6 2.00 19 | 0-205-12345-X 6 3.50 20 | 0-205-12345-X 3 4.00 21 | 0-205-12345-X 5 3.00 22 | 0-206-12345-X 3 24.00 23 | -------------------------------------------------------------------------------- /ch8/8.9.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | std::istream &read(std::istream &is) { 6 | //auto old_state = is.rdstate(); 7 | is.clear(); 8 | std::string str; 9 | while (is >> str) 10 | std::cout << str << " "; 11 | std::cout << std::endl; 12 | is.clear(); 13 | //is.setstate(old_state); 14 | return is; 15 | } 16 | 17 | int main() { 18 | std::string str; 19 | std::getline(std::cin, str); 20 | std::istringstream iss(str); 21 | read(iss); 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /ch9/9.1.md: -------------------------------------------------------------------------------- 1 | (a) List. Since the sequence of the words need to be alphabetical, the container needs to support insert in the middle effeciently. 2 | 3 | (b) Deque. The container needs to support insert/delete in the front and back effeciently. 4 | 5 | (c) Vector. There is no need to use other containers. And to sort the numbers in container, random access is usually needed. 6 | -------------------------------------------------------------------------------- /ch9/9.10.md: -------------------------------------------------------------------------------- 1 | vector v1; 2 | const vector v2; 3 | //auto it1 = v1.begin(), it2 = v2.begin(); 4 | // it1 and it2 have different type, thus need be seperated into two statements. 5 | auto it1 = v1.begin(); 6 | // the type of `it1` is `vector::iterator` 7 | auto it2 = v2.begin(); 8 | // the type of `it2` is `vector::const_iterator` 9 | auto it3 = v1.cbegin(), it4 = v2.cbegin(); 10 | // the type of `it3` and `it4` is `vector::const_iterator` 11 | -------------------------------------------------------------------------------- /ch9/9.11.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using std::vector; 3 | 4 | int main() { 5 | vector v1; // Empty 6 | vector v2(v1); // Empty 7 | vector v3 = v1; // Empty 8 | vector v4{1, 2, 3}; // 3 elements: 1, 2, 3 9 | vector v5 = {1, 2, 3}; // 3 elements: 1, 2, 3 10 | vector v6(v5.begin(), v5.end()); // 3 elements: 1, 2, 3 11 | 12 | vector v7(5); // 5 elements: 0, 0, 0, 0, 0 13 | vector v8(5, 1); // 5 elements: 1, 1, 1, 1, 1 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /ch9/9.13.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::list li{1, 2, 3}; 7 | std::vector vi{4, 5, 6}; 8 | 9 | std::vector vd1(li.begin(), li.end()); 10 | std::vector vd2(vi.begin(), vi.end()); 11 | 12 | std::cout << vd1[0] << " " << vd2[0] << std::endl; 13 | 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /ch9/9.14.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | std::list lc{"aaa", "bbb", "ccc"}; 8 | std::vector vs; 9 | 10 | vs.assign(lc.begin(), lc.end()); 11 | 12 | std::cout << vs[0] << std::endl; 13 | 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /ch9/9.15.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::vector v1 = {1, 3, 5, 7, 9, 12}; 6 | std::vector v2 = {1, 3, 9}; 7 | 8 | std::cout << (v1 < v2 ? "v1 < v2" : "v2 < v1") << std::endl; 9 | 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /ch9/9.17.md: -------------------------------------------------------------------------------- 1 | The constraints are: 2 | 3 | 1. the lefthand and righthand operands must have the same container type and element type. 4 | 2. the element of the container must support the `<` operator. 5 | -------------------------------------------------------------------------------- /ch9/9.18.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::deque words; 7 | std::string word; 8 | while (std::cin >> word) 9 | words.push_back(word); 10 | 11 | for (std::deque::const_iterator it = words.cbegin(); 12 | it != words.cend(); ++it) 13 | std::cout << *it << std::endl; 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /ch9/9.19.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include // 1. Include header 3 | #include 4 | #include 5 | 6 | int main() { 7 | //std::deque words; 8 | std::list words; // 2. Define variable 9 | std::string word; 10 | while (std::cin >> word) 11 | words.push_back(word); 12 | 13 | //for (std::deque::const_iterator it = words.cbegin(); 14 | // 3. Iterator. Note that if `auto` is used here, then nothing needs change. 15 | for (std::list::const_iterator it = words.cbegin(); 16 | it != words.cend(); ++it) 17 | std::cout << *it << std::endl; 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /ch9/9.2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::list> ldi; 6 | 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /ch9/9.20.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::list input; 7 | std::deque even, odd; 8 | 9 | for (int i; std::cin >> i; ) 10 | input.push_back(i); 11 | 12 | for (auto it = input.cbegin(); it != input.cend(); ++it) 13 | if (*it % 2) 14 | odd.push_back(*it); 15 | else 16 | even.push_back(*it); 17 | 18 | std::cout << "Odd: "; 19 | for (const auto &i : odd) 20 | std::cout << i << " "; 21 | std::cout << std::endl; 22 | 23 | std::cout << "Even: "; 24 | for (const auto &i : even) 25 | std::cout << i << " "; 26 | std::cout << std::endl; 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /ch9/9.21.md: -------------------------------------------------------------------------------- 1 | The member function `insert(p, t)` has the same effect on both `list` and `vector` containers, but the cost is different. Inserting an element into `list` is cheap, while inserting an element into `vector` will cause all the elements after the newly inserted element be moved. Thus every time the `while` loop body is excuted, all elements in the `vector` are moved backward, and new element is inserted in the front of the `vector`. 2 | -------------------------------------------------------------------------------- /ch9/9.22.md: -------------------------------------------------------------------------------- 1 | vector::iterator iter = iv.begin(), 2 | mid = iv.begin() + iv.size()/2; 3 | while (iter != mid) { 4 | if (*iter == some_val) { 5 | iv.insert(iter, 2 * some_val); // Error, we should update the iter 6 | iter = iv.insert(iter, 2 * some_val); 7 | ++iter; // Increament to point to the original value 8 | } 9 | ++iter; // Increment to point to the next value 10 | } 11 | -------------------------------------------------------------------------------- /ch9/9.23.md: -------------------------------------------------------------------------------- 1 | The values of them are all copies of `c[0]`. 2 | -------------------------------------------------------------------------------- /ch9/9.24.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::vector vi; 6 | 7 | // All of them will cause program terminate in VS2015. 8 | //int i1 = vi.at(0); 9 | //int i2 = vi[0]; 10 | //int i3 = vi.front(); 11 | //int i4 = *vi.begin(); 12 | 13 | //std::cout << i1 << " " << i2 << " " << i3 << " " << i4 << std::endl; 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /ch9/9.25.md: -------------------------------------------------------------------------------- 1 | If `elem1` and `elem2` are equal, then no element will be removed from the container. 2 | 3 | If `elem2` or both `elem1` and `elem2` are the off-the-end iterator, then all elements from `elem1` to the last element in the container will be removed. 4 | -------------------------------------------------------------------------------- /ch9/9.27.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::forward_list fli{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 6 | auto pre = fli.before_begin(); 7 | auto cur = fli.begin(); 8 | while (cur != fli.end()) { 9 | if (*cur % 2) { 10 | cur = fli.erase_after(pre); 11 | } else { 12 | pre = cur; 13 | ++cur; 14 | } 15 | } 16 | 17 | for (const auto &i : fli) 18 | std::cout << i << " "; 19 | std::cout << std::endl; 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /ch9/9.29.md: -------------------------------------------------------------------------------- 1 | `vec.resize(100)` will append 75 value initialized elements at the end of `vec`. 2 | 3 | `vec.resize(10)` will remove 90 elements from the end of `vec`. 4 | -------------------------------------------------------------------------------- /ch9/9.3.md: -------------------------------------------------------------------------------- 1 | The constraints for two iterators, `begin` and `end`, forming an iterator range are 2 | 3 | 1. They refer to elements of, or one past the end of, the same container. 4 | 2. `end` must not precede `begin`. 5 | -------------------------------------------------------------------------------- /ch9/9.30.md: -------------------------------------------------------------------------------- 1 | If we use `resize` to expand a container, then the element of the container must have default constructor. 2 | -------------------------------------------------------------------------------- /ch9/9.32.md: -------------------------------------------------------------------------------- 1 | It is not legal. The order of evaluation of the arguments in function `insert` is undefined, so that if the second argument is evalated first, then the program logic will be wrong. 2 | -------------------------------------------------------------------------------- /ch9/9.33.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using std::vector; 3 | 4 | int main() { 5 | vector v{1, 2, 3, 4, 5}; 6 | 7 | auto begin = v.begin(); 8 | while (begin != v.end()) { 9 | ++begin; 10 | begin = v.insert(begin, 42); 11 | //v.insert(begin, 42); 12 | // Iterator `begin` will become invalid after insert, thus if we don't 13 | // update the iterator, any usage of this iterator will have undefined 14 | // behaviours. 15 | ++begin; 16 | } 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /ch9/9.34.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | //std::vector vi{1, 2, 3, 4}; 5 | std::vector vi{2, 4}; 6 | 7 | // If the container contains any odd values, the loop will continue 8 | // infinitely. 9 | auto iter = vi.begin(); 10 | while (iter != vi.end()) { // The loop body should be a block. 11 | if (*iter % 2) 12 | iter = vi.insert(iter, *iter); 13 | ++iter; 14 | } 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /ch9/9.35.md: -------------------------------------------------------------------------------- 1 | The `capacity` of a vector is how many elements the vector **can hold**. 2 | 3 | The `size` of a vector is how many elements the vector **already holds**. 4 | -------------------------------------------------------------------------------- /ch9/9.36.md: -------------------------------------------------------------------------------- 1 | No. 2 | -------------------------------------------------------------------------------- /ch9/9.37.md: -------------------------------------------------------------------------------- 1 | A `list` does not support random access, and element of `list` is stored seperately in memory. There is no need to reallocate its elements, and thus no need to preallocate memory. So the "`capacity`" of a `list` is the same with its `size`. 2 | 3 | An `array` has a fixed size, there is also no need to reallocate its elements, and thus no need to preallocate memory. So the "`capacity`" of an `array` is the same with its `size` too. 4 | -------------------------------------------------------------------------------- /ch9/9.39.md: -------------------------------------------------------------------------------- 1 | vector svec; 2 | svec.reserve(1024); // Preallocate memory for 1024 `string`s 3 | string word; 4 | while (cin >> word) // Read stirngs into `svec` 5 | svec.push_back(word); 6 | svec.resize(svec.size()+svec.size()/2); 7 | // Reallocate memory, if current capacity is greater then this argument, 8 | // nothing happened, else expand the size to at least the same as the 9 | // argument. 10 | -------------------------------------------------------------------------------- /ch9/9.4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | bool hasValue(std::vector::const_iterator begin, 6 | std::vector::const_iterator end, 7 | int k) { 8 | for (auto it = begin; it != end; ++it) 9 | if (k == *it) 10 | return true; 11 | return false; 12 | } 13 | 14 | int main() { 15 | std::string str; 16 | std::getline(std::cin, str); 17 | std::istringstream iss(str); 18 | std::vector vi; 19 | int k; 20 | while (iss >> k) 21 | vi.push_back(k); 22 | std::cin >> k; 23 | std::cout << hasValue(vi.cbegin(), vi.cend(), k) << std::endl; 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /ch9/9.40.md: -------------------------------------------------------------------------------- 1 | If the program reads 256 words, the `capacity` is 1024. 2 | 3 | If the program reads 512 words, the `capacity` is 1024. 4 | 5 | If the program reads 1000 words, the `capacity` is 1024. 6 | 7 | If the program reads 1048 words, the `capacity` is *at least* 1048. 8 | -------------------------------------------------------------------------------- /ch9/9.41.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::vector vc{'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'}; 7 | std::string str(vc.cbegin(), vc.cend()); 8 | 9 | std::cout << str << std::endl; 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /ch9/9.42.md: -------------------------------------------------------------------------------- 1 | We can call `s.reserve(100)` to preallocate the space for the string `s`. 2 | -------------------------------------------------------------------------------- /ch9/9.45.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | std::string fixName(const std::string &name, 5 | const std::string &prefix, 6 | const std::string &postfix) { 7 | std::string newName = name; 8 | std::string pref = prefix + " "; 9 | newName.insert(newName.begin(), pref.begin(), pref.end()); 10 | return newName.append(" " + postfix); 11 | } 12 | 13 | int main() { 14 | std::cout << fixName("James", "Mr.", "Jr.") << std::endl; 15 | 16 | std::string name, prefix, postfix; 17 | std::cin >> name >> prefix >> postfix; 18 | std::cout << fixName(name, prefix, postfix) << std::endl; 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /ch9/9.48.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::string numbers("0123456789"), name("r2d2"); 6 | auto pos = numbers.find(name); // std::string::npos 7 | if (pos != std::string::npos) 8 | std::cout << pos << std::endl; 9 | else 10 | std::cout << "npos" << std::endl; 11 | 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /ch9/9.50.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::vector vs; 7 | for (std::string number; std::cin >> number; vs.push_back(number)) {} 8 | //int sum = 0; 9 | double sum = 0; 10 | for (const auto &s : vs) 11 | //sum += stoi(s); 12 | sum += stod(s); 13 | std::cout << "The sum is " << sum << std::endl; 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /ch9/9.6.md: -------------------------------------------------------------------------------- 1 | The iterator of `list` does not support iterator arithmetic, including relational operators like `>`, `<`. Thus the condition for the `while loop` should be `iter1 != iter2`. 2 | -------------------------------------------------------------------------------- /ch9/9.7.md: -------------------------------------------------------------------------------- 1 | `std::vector::size_type`. 2 | -------------------------------------------------------------------------------- /ch9/9.8.md: -------------------------------------------------------------------------------- 1 | We can use `std::list::const_iterator` or `std::list::iterator` to read elements, and use `std::list::iterator` to write them. 2 | -------------------------------------------------------------------------------- /ch9/9.9.md: -------------------------------------------------------------------------------- 1 | Those that start with a `c` return the `const` version of the related iterator. For example, `begin()` will return an `iterator` while `cbegin()` will return a `const_iterator`. 2 | --------------------------------------------------------------------------------