diff --git a/ch13/README.md b/ch13/README.md index 3546cdfb..889d5956 100644 --- a/ch13/README.md +++ b/ch13/README.md @@ -160,3 +160,24 @@ TextQuery& operator=(const TextQuery) = delete; QueryResult(const QueryResult&) = delete; QueryResult& operator=(const QueryResult) = delete; ``` + +## [Exercise 13.22](ex13_22.h) + +## Exercise 13.23: +>Compare the copy-control members that you wrote for the solutions to the previous section’s exercises to the code presented here. Be sure you understand the differences, if any, between your code and ours. + +Check 13.22. + +## Exercise 13.24: +>What would happen if the version of HasPtr in this section didn’t define a destructor? What if HasPtr didn’t define the copy constructor? + +If `HasPtr` didn't define a destructor, memory leak will happened. If `HasPtr` didn't define the copy constructor, when assignment happened, just points copied, the string witch `ps` points haven't been copied. + +## Exercise 13.25: +>Assume we want to define a version of StrBlob that acts like a value. Also assume that we want to continue to use a shared_ptr so that our StrBlobPtr class can still use a weak_ptr to the vector. Your revised class will need a copy constructor and copy-assignment operator but will not need a destructor. Explain what the copy constructor and copyassignment operators must do. Explain why the class does not need a destructor. + +Copy constructor and copy-assignment operator should dynamicly allocate memory for its own , rather than share the object with the right hand operand. + +`StrBlob` is using smart pointers which can be managed with synthesized destructor, If an object of `StrBlob` is out of scope, the destructor for std::shared_ptr will be called automaticaly to free the memory dynamically allocated when the `use_count` goes to 0. + +## Exercise 13.26 [hpp](ex13_26.h) | [cpp](ex13_26.cpp) diff --git a/ch13/ex13.20.21.22.cpp b/ch13/ex13.20.21.22.cpp deleted file mode 100644 index 704e06ad..00000000 --- a/ch13/ex13.20.21.22.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/*************************************************************************** - * @file main.cpp - * @author Alan.W - * @date 01 JAN 2014 - * @remark - ***************************************************************************/ -//! -//! Exercise 13.20: -//! Explain what happens when we copy, assign, or destroy objects of our TextQuery -//! and QueryResult classes from § 12.3 (p. 484). -// -//! -//! Exercise 13.21: -//! Do you think the TextQuery and QueryResult classes need to define their own -//! versions of the copy-control members? If so, why? If not, why not? Implement -//! whichever copy-control operations you think these classes require. -//! -// No copy-control members needed. -// Because, all these classes are using smart poitners to manage dynamic memory which -// can be freed automatically by calling synthesized destructors. The objects of these -// classes should share the same dynamic memory.Hence no user-defined version needed -// as well. -//! -//! Exercise 13.22: -//! Assume that we want HasPtr to behave like a value. That is, each object should -//! have its own copy of the string to which the objects point. We’ll show the -//! definitions of the copy-control members in the next section. However, you already -//! know everything you need to know to implement these members. Write the HasPtr copy -//! constructor and copy-assignment operator before reading on. -// Discussing on SO: -// http://stackoverflow.com/questions/20864892/is-it-a-good-practice-to-point-to-a-new-address-on-free-store-when-dynamicly-all -//! - -#include -#include -#include -#include - -//! for ex13.22 -//! value like. -class HasPtr -{ -public: - //! default constructor. - HasPtr(const std::string &s = std::string()): - ps(new std::string(s)), i(0) { } - - //! copy constructor. - HasPtr(const HasPtr& hp) : ps(new std::string(*hp.ps)), i(hp.i) { } - - //! ex13.22 value like version copy assignment operator - HasPtr& - operator = (const HasPtr& hp); - - //! destructor. - ~HasPtr() - { - delete ps; - } - -private: - std::string *ps; - int i; -}; - -int main() -{ - - HasPtr h1("111"), h2("222"); - - h1 = h2; - - - - - return 0; -} - - -HasPtr& -HasPtr::operator = (const HasPtr &hp) -{ - delete ps; - ps = new std::string(*hp.ps); - - i = hp.i; - - return *this; -} diff --git a/ch13/ex13.25.26/StrBlob.h b/ch13/ex13.25.26/StrBlob.h deleted file mode 100644 index acefe6db..00000000 --- a/ch13/ex13.25.26/StrBlob.h +++ /dev/null @@ -1,199 +0,0 @@ -/*************************************************************************** - * @file main.cpp - * @author Alan.W - * @date 01 JAN 2014 - * @remark - ***************************************************************************/ -//! -//! Exercise 13.25: -//! Assume we want to define a version of StrBlob that acts like a value. Also -//! assume that we want to continue to use a shared_ptr so that our StrBlobPtr -//! class can still use a weak_ptr to the vector. Your revised class will need -//! a copy constructor and copy-assignment operator but will not need a destructor. -//! Explain what the copy constructor and copy-assignment operators must do. -//! Explain why the class does not need a destructor. -//! -// Copy constructor and copy-assignment operator should dynamicly allocate memory -// for its own , rather than share the object with the right hand operand. -// -// StrBlob is using smart pointers which can be managed with synthesized destructor -// If an object of StrBlob is out of scope, the desstructor for std::shared_ptr -// will be called automaticaly to free the memory dynamicly allocated when the -// use count goes to 0. -//! -//! Exercise 13.26: -//! Write your own version of the StrBlob class described in the previous exercise. -//! - - -#ifndef STRBLOB_H -#define STRBLOB_H - -#include -#include -#include -#include -#include - -// forward declaration needed for friend declaration in StrBlob -class StrBlobPtr; - -class StrBlob -{ - friend class StrBlobPtr; -public: - typedef std::vector::size_type size_type; - - // constructors - StrBlob() : data(std::make_shared>()) { } - StrBlob(std::initializer_list il); - - //! copy constructor for ex13.26 - StrBlob(const StrBlob& sb); - - //! copy-assignment operator for ex13.26 - StrBlob& - operator = (const StrBlob &sb); - - // size operations - size_type size() const { return data->size(); } - bool empty() const { return data->empty(); } - - // add and remove elements - void push_back(const std::string &t) { data->push_back(t); } - void pop_back(); - - // element access - std::string& front(); - std::string& back(); - - // interface to StrBlobPtr - StrBlobPtr begin(); // can't be defined until StrBlobPtr is - StrBlobPtr end(); -private: - std::shared_ptr> data; - // throws msg if data[i] isn't valid - void check(size_type i, const std::string &msg) const; -}; - -// constructor -inline -StrBlob::StrBlob(std::initializer_list il): - data(std::make_shared>(il)) { } - -//! copy constructor for ex13.26 -inline -StrBlob::StrBlob(const StrBlob &sb) : - data(std::make_shared>(*sb.data)){ } - -//! copy-assignment operator for ex13.26 -inline StrBlob& -StrBlob::operator =(const StrBlob &sb) -{ - auto p = std::make_shared>(*sb.data); - std::swap(data,p); - - return *this; -} - - - -// StrBlobPtr throws an exception on attempts to access a nonexistent element -class StrBlobPtr -{ - friend bool eq(const StrBlobPtr&, const StrBlobPtr&); -public: - StrBlobPtr(): curr(0) { } - StrBlobPtr(StrBlob &a, size_t sz = 0) : wptr(a.data), curr(sz) { } - - //! newly overloaded why? - StrBlobPtr(const StrBlob &a, const size_t sz = 0) : wptr(a.data), curr(sz) { } - - std::string& deref() const; - StrBlobPtr& incr(); // prefix version - StrBlobPtr& decr(); // prefix version -private: - // check returns a shared_ptr to the vector if the check succeeds - std::shared_ptr> - check(std::size_t, const std::string&) const; - - // store a weak_ptr, which means the underlying vector might be destroyed - std::weak_ptr> wptr; - std::size_t curr; // current position within the array -}; - -inline -std::string& StrBlobPtr::deref() const -{ - auto p = check(curr, "dereference past end"); - return (*p)[curr]; // (*p) is the vector to which this object points -} - -inline -std::shared_ptr> -StrBlobPtr::check(std::size_t i, const std::string &msg) const -{ - auto ret = wptr.lock(); // is the vector still around? - if (!ret) - throw std::runtime_error("unbound StrBlobPtr"); - - if (i >= ret->size()) - throw std::out_of_range(msg); - return ret; // otherwise, return a shared_ptr to the vector -} - -// prefix: return a reference to the incremented object -inline -StrBlobPtr& StrBlobPtr::incr() -{ - // if curr already points past the end of the container, can't increment it - check(curr, "increment past end of StrBlobPtr"); - ++curr; // advance the current state - return *this; -} - -inline -StrBlobPtr& StrBlobPtr::decr() -{ - // if curr is zero, decrementing it will yield an invalid subscript - --curr; // move the current state back one element} - check(-1, "decrement past begin of StrBlobPtr"); - return *this; -} - -// begin and end members for StrBlob -inline -StrBlobPtr -StrBlob::begin() -{ - return StrBlobPtr(*this); -} - -inline -StrBlobPtr -StrBlob::end() -{ - auto ret = StrBlobPtr(*this, data->size()); - return ret; -} - -// named equality operators for StrBlobPtr -inline -bool eq(const StrBlobPtr &lhs, const StrBlobPtr &rhs) -{ - auto l = lhs.wptr.lock(), r = rhs.wptr.lock(); - // if the underlying vector is the same - if (l == r) - // then they're equal if they're both null or - // if they point to the same element - return (!r || lhs.curr == rhs.curr); - else - return false; // if they point to difference vectors, they're not equal -} - -inline -bool neq(const StrBlobPtr &lhs, const StrBlobPtr &rhs) -{ - return !eq(lhs, rhs); -} -#endif diff --git a/ch13/ex13.25.26/main.cpp b/ch13/ex13.25.26/main.cpp deleted file mode 100644 index eef05485..00000000 --- a/ch13/ex13.25.26/main.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/*************************************************************************** - * @file main.cpp - * @author Alan.W - * @date 01 JAN 2014 - * @remark - ***************************************************************************/ -//! -//! Exercise 13.25: -//! Assume we want to define a version of StrBlob that acts like a value. Also -//! assume that we want to continue to use a shared_ptr so that our StrBlobPtr -//! class can still use a weak_ptr to the vector. Your revised class will need -//! a copy constructor and copy-assignment operator but will not need a destructor. -//! Explain what the copy constructor and copy-assignment operators must do. -//! Explain why the class does not need a destructor. -//! -// Copy constructor and copy-assignment operator should dynamicly allocate memory -// for its own , rather than share the object with the right hand operand. -// -// StrBlob is using smart pointers which can be managed with synthesized destructor -// If an object of StrBlob is out of scope, the desstructor for std::shared_ptr -// will be called automaticaly to free the memory dynamicly allocated when the -// use count goes to 0. -//! -//! Exercise 13.26: -//! Write your own version of the StrBlob class described in the previous exercise. -//! - -#include -#include -#include -#include -#include - -//! for ex13.22 -//! value like. -class HasPtr -{ -public: - //! default constructor. - HasPtr(const std::string &s = std::string()): - ps(new std::string(s)), i(0) { } - - //! copy constructor. - HasPtr(const HasPtr& hp) : ps(new std::string(*hp.ps)), i(hp.i) { } - - //! ex13.22 value like version copy assignment operator - HasPtr& - operator = (const HasPtr& hp); - - //! destructor. - ~HasPtr() - { - delete ps; - } - -private: - std::string *ps; - int i; -}; - - - -int main() -{ - StrBlob sb1({"111","222","333"}); - StrBlob sb2(sb1) , sb3; - - sb3 = sb2; - - return 0; -} - - -HasPtr& -HasPtr::operator = (const HasPtr &hp) -{ - delete ps; - ps = new std::string(*hp.ps); - - i = hp.i; - - return *this; -} diff --git a/ch13/ex13_05.h b/ch13/ex13_05.h index 3670a145..46c5bc85 100644 --- a/ch13/ex13_05.h +++ b/ch13/ex13_05.h @@ -17,7 +17,7 @@ class HasPtr { public: HasPtr(const std::string &s = std::string()) : ps(new std::string(s)), i(0) { } - HasPtr(const HasPtr& hp) : ps(new std::string(*hp.ps)), i(hp.i) { } + HasPtr(const HasPtr& hp) : ps(hp.ps), i(hp.i) { } private: std::string *ps; int i; diff --git a/ch13/ex13_08.h b/ch13/ex13_08.h index 8d49092b..7f50f76a 100644 --- a/ch13/ex13_08.h +++ b/ch13/ex13_08.h @@ -18,9 +18,9 @@ class HasPtr { public: HasPtr(const std::string &s = std::string()) : ps(new std::string(s)), i(0) { } - HasPtr(const HasPtr &hp) : ps(new std::string(*hp.ps)), i(hp.i) { } + HasPtr(const HasPtr &hp) : ps(hp.ps), i(hp.i) { } HasPtr& operator=(const HasPtr &hp) { - ps = new std::string(*hp.ps); + ps = hp.ps; i = hp.i; return *this; } diff --git a/ch13/ex13_11.h b/ch13/ex13_11.h index c36d4073..93b28a84 100644 --- a/ch13/ex13_11.h +++ b/ch13/ex13_11.h @@ -17,15 +17,15 @@ class HasPtr { public: HasPtr(const std::string &s = std::string()) : ps(new std::string(s)), i(0) { } - HasPtr(const HasPtr &hp) : ps(new std::string(*hp.ps)), i(hp.i) { } + HasPtr(const HasPtr &hp) : ps(hp.ps), i(hp.i) { } HasPtr& operator=(const HasPtr &hp) { - ps = new std::string(*hp.ps); + ps = hp.ps; i = hp.i; return *this; } ~HasPtr() { delete ps; - } + } private: std::string *ps; int i; diff --git a/ch13/ex13_22.h b/ch13/ex13_22.h new file mode 100644 index 00000000..837a5556 --- /dev/null +++ b/ch13/ex13_22.h @@ -0,0 +1,40 @@ +// +// ex13_22.h +// Exercise 13.22 +// +// Created by pezy on 1/13/15. +// Copyright (c) 2015 pezy. All rights reserved. +// +// Assume that we want HasPtr to behave like a value. +// That is, each object should have its own copy of the string to which the objects point. +// We¡¯ll show the definitions of the copy-control members in the next section. +// However, you already know everything you need to know to implement these members. +// Write the HasPtr copy constructor and copyassignment operator before reading on. +// +// See ex13_11.h + +#ifndef CP5_ex13_11_h +#define CP5_ex13_11_h + +#include + +class HasPtr { +public: + HasPtr(const std::string &s = std::string()) : ps(new std::string(s)), i(0) { } + HasPtr(const HasPtr &hp) : ps(new std::string(*hp.ps)), i(hp.i) { } + HasPtr& operator=(const HasPtr &hp) { + auto new_p = new std::string(*hp.ps); + delete ps; + ps = new_p; + i = hp.i; + return *this; + } + ~HasPtr() { + delete ps; + } +private: + std::string *ps; + int i; +}; + +#endif diff --git a/ch13/ex13_26.cpp b/ch13/ex13_26.cpp new file mode 100644 index 00000000..a0fee4f7 --- /dev/null +++ b/ch13/ex13_26.cpp @@ -0,0 +1,27 @@ +// +// ex13_26.cpp +// Exercise 13.26 +// +// Created by pezy on 1/19/15. +// Copyright (c) 2014 pezy. All rights reserved. +// +// Write your own version of the StrBlob class described in the previous exercise. +// +// @See ex12_22 and ex13_25 + +#include "ex13_26.h" + +ConstStrBlobPtr StrBlob::begin() const // should add const +{ + return ConstStrBlobPtr(*this); +} +ConstStrBlobPtr StrBlob::end() const // should add const +{ + return ConstStrBlobPtr(*this, data->size()); +} + +StrBlob& StrBlob::operator=(const StrBlob& sb) +{ + data = std::make_shared>(*sb.data); + return *this; +} diff --git a/ch13/ex13_26.h b/ch13/ex13_26.h new file mode 100644 index 00000000..07734d3d --- /dev/null +++ b/ch13/ex13_26.h @@ -0,0 +1,93 @@ +// +// ex13_26.cpp +// Exercise 13.26 +// +// Created by pezy on 1/19/15. +// Copyright (c) 2014 pezy. All rights reserved. +// +// Write your own version of the StrBlob class described in the previous exercise. +// +// @See ex12_22 and ex13_25 + +#ifndef CP5_ex13_26_h +#define CP5_ex13_26_h + +#include +#include +#include +#include +#include + +using std::vector; using std::string; + +class ConstStrBlobPtr; + +class StrBlob { +public: + using size_type = vector::size_type; + friend class ConstStrBlobPtr; + + ConstStrBlobPtr begin() const; + ConstStrBlobPtr end() const; + + StrBlob():data(std::make_shared>()) { } + StrBlob(std::initializer_list il):data(std::make_shared>(il)) { } + + // copy constructor + StrBlob(const StrBlob& sb) : data(std::make_shared>(*sb.data)) {} + // copyassignment operators + StrBlob& operator=(const StrBlob& sb); + + size_type size() const { return data->size(); } + bool empty() const { return data->empty(); } + + void push_back(const string &t) { data->push_back(t); } + void pop_back() { + check(0, "pop_back on empty StrBlob"); + data->pop_back(); + } + const std::string& front() { + check(0, "front on empty StrBlob"); + return data->front(); + } + const std::string& back() { + check(0, "back on empty StrBlob"); + return data->back(); + } + +private: + void check(size_type i, const string &msg) const { + if (i >= data->size()) throw std::out_of_range(msg); + } + +private: + std::shared_ptr> data; +}; + +class ConstStrBlobPtr { +public: + ConstStrBlobPtr():curr(0) { } + ConstStrBlobPtr(const StrBlob &a, size_t sz = 0):wptr(a.data), curr(sz) { } // should add const + bool operator!=(ConstStrBlobPtr& p) {return p.curr != curr; } + const string& deref() const { // return value should add const + auto p = check(curr, "dereference past end"); + return (*p)[curr]; + } + ConstStrBlobPtr& incr() { + check(curr, "increment past end of StrBlobPtr"); + ++curr; + return *this; + } + +private: + std::shared_ptr> check(size_t i, const string &msg) const { + auto ret = wptr.lock(); + if (!ret) throw std::runtime_error("unbound StrBlobPtr"); + if (i >= ret->size()) throw std::out_of_range(msg); + return ret; + } + std::weak_ptr> wptr; + size_t curr; +}; + +#endif