diff --git a/ch13/README.md b/ch13/README.md index 7cab33b0..93b69c60 100644 --- a/ch13/README.md +++ b/ch13/README.md @@ -265,7 +265,8 @@ for_each(elements, first_free, [this](std::string &rhs){ alloc.destroy(&rhs); }) @Mooophy: The new version is better. Compared to the old one, it doesn't need to worry about the order and decrement.So more straightforward and handy. The only thing to do for using this approach is to add "&" to build the pointers to string pointers. -## Exercise 13.44: Write a class named String that is a simplified version of the library string class. Your class should have at least a default constructor and a constructor that takes a pointer to a C-style string. Use an allocator to allocate memory that your String class uses. +## Exercise 13.44: +>Write a class named String that is a simplified version of the library string class. Your class should have at least a default constructor and a constructor that takes a pointer to a C-style string. Use an allocator to allocate memory that your String class uses. [hpp](ex13_44_47.h) | [cpp](ex13_44_47.cpp) | [Test](ex13_48.cpp) @@ -307,3 +308,95 @@ int&& r4 = vi[0] * f(); ## Exercise 13.47 [hpp](ex13_44_47.h) | [cpp](ex13_44_47.cpp) ## [Exercise 13.48](ex13_48.cpp) + +## Exercise 13.49: +>Add a move constructor and move-assignment operator to your StrVec, String, and Message classes. + +- StrVec: [hpp](ex13_49_StrVec.h) | [cpp](ex13_49_StrVec.cpp) +- String: [hpp](ex13_49_String.h) | [cpp](ex13_49_String.cpp) +- Message:[hpp](ex13_49_Message.h) | [cpp](ex13_49_Message.cpp) + +## Exercise 13.50: +> Put print statements in the move operations in your String class and rerun the program from exercise 13.48 in 13.6.1 (p. 534) that used a vector to see when the copies are avoided. + +```cpp +String baz() +{ + String ret("world"); + return ret; // first avoided +} + +String s5 = baz(); // second avoided +``` + +## Exercise 13.51: +>Although `unique_ptrs` cannot be copied, in 12.1.5 (p. 471) we wrote a clone function that returned a unique_ptr by value. Explain why that function is legal and how it works. + +In the second assignment, we assign from the result of a call to getVec. That expression is an rvalue. In this case, both assignment operators are viable—we can bind the result of getVec to either operator’s parameter. Calling the copy-assignment operator requires a conversion to const, whereas StrVec&& is an exact match. Hence, the second assignment uses the move-assignment operator. + +```cpp +unique_ptr clone(int p) { + // ok: explicitly create a unique_ptr from int* + return unique_ptr(new int(p)); +} +``` + +the result of a call to `clone` is an **rvalue**, so it uses the move-assignment operator rather than copy-assignment operator. Thus, it is legal and can pretty work. + +## Exercise 13.52: +>Explain in detail what happens in the assignments of the `HasPtr` objects on page 541. In particular, describe step by step what happens to values of `hp`, `hp2`, and of the `rhs` parameter in the `HasPtr` assignment operator. + +`rhs` parameter is nonreference, which means the parameter is **copy initialized**. Depending on the type of the argument, copy initialization uses either the *copy constructor* or the *move constructor*. + +**lvalues are copied and rvalues are moved.** + +Thus, in `hp = hp2;`, `hp2` is an lvalue, copy constructor used to copy `hp2`. In `hp = std::move(hp2);`, move constructor moves `hp2`. + +## Exercise 13.53: +>As a matter of low-level efficiency, the `HasPtr` assignment operator is not ideal. Explain why. Implement a copy-assignment and move-assignment operator for `HasPtr` and compare the operations executed in your new move-assignment operator versus the copy-and-swap version. + +nothing to say, just see the versus codes: + +[hpp](ex13_53.h) | [cpp](ex13_53.cpp) | [Test](ex13_53_TEST.cpp) + +see more information at [this question && answer](http://stackoverflow.com/questions/21010371/why-is-it-not-efficient-to-use-a-single-assignment-operator-handling-both-copy-a). + +## Exercise 13.54: +>What would happen if we defined a `HasPtr` move-assignment operator but did not change the copy-and-swap operator? Write code to test your answer. + +```sh +error: ambiguous overload for 'operator=' (operand types are 'HasPtr' and 'std::remove_reference::type {aka HasPtr}') +hp1 = std::move(*pH); +^ +``` + +## Exercise 13.55: +>Add an rvalue reference version of `push_back` to your `StrBlob`. + +```cpp +void push_back(string &&s) { data->push_back(std::move(s)); } +``` + +## Exercise 13.56: +>What would happen if we defined sorted as: +```cpp +Foo Foo::sorted() const & { + Foo ret(*this); + return ret.sorted(); +} +``` + +recursion and stack overflow. + +## Exercise 13.57: +>What if we defined sorted as: +```cpp +Foo Foo::sorted() const & { return Foo(*this).sorted(); } +``` + +ok, it will call the move version. + +## Exercise 13.58: +>Write versions of class Foo with print statements in their sorted functions to test your answers to the previous two exercises. + +[Exercise 13.58](ex13_58.cpp) diff --git a/ch13/ex13.49.50/folder.cpp b/ch13/ex13.49.50/folder.cpp deleted file mode 100644 index 12651a70..00000000 --- a/ch13/ex13.49.50/folder.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "folder.h" -#include "message.h" - - - -/** - * @brief copy constructor - * @param rhs - * @note this function is not using the save member of Message class - * that will access back to Folder class and insert into messages, - * which is a meaningless operation. - */ -Folder::Folder(const Folder &rhs): - name(rhs.name), messages(rhs.messages) -{ - for(const auto &m :messages) - m->folders.insert(this); -} - -Folder& -Folder::operator = (const Folder& rhs) -{ - for(const auto &m : messages) - m->folders.erase(this); - - name = rhs.name; - messages = rhs.messages; - - for(const auto &m :messages) - m->folders.insert(this); - - return *this; -} - -Folder::~Folder() -{ - for(const auto &m : messages) - m->folders.erase(this); -} - - -void Folder::addMsg(Message *p_m) -{ - messages.insert(p_m); -} - -void Folder::remMsg(Message *p_m) -{ - messages.erase(p_m); -} - - -void swap(Folder &lhs, Folder &rhs) -{ - using std::swap; - - //! first, remove all messages that point to the both folders - for(const auto &m : lhs.messages) - m->remFld(&lhs); - for(const auto &m : rhs.messages) - m->remFld(&rhs); - - //! second, swap - swap(lhs.name, rhs.name); - swap(lhs.messages, rhs.messages); - - //! finally add pointers from new set of messgaes to new folder - for (const auto &m : lhs.messages) - m->addFld(&lhs); - for (const auto &m : rhs.messages) - m->addFld(&rhs); - -} - diff --git a/ch13/ex13.49.50/folder.h b/ch13/ex13.49.50/folder.h deleted file mode 100644 index 7f523b9f..00000000 --- a/ch13/ex13.49.50/folder.h +++ /dev/null @@ -1,48 +0,0 @@ -/*************************************************************************** - * @file folder.h - * @author Alan.W - * @date 04 JAN 2014 - * @remark - ***************************************************************************/ -#ifndef FOLDER_H -#define FOLDER_H - -#include -#include - -class Message; - -class Folder -{ - friend class Message; - friend void swap(Message &lhs, Message &rhs); - friend void swap(Folder& lhs, Folder& rhs); -public: - //! default constructor - explicit Folder(const std::string& s = ""): - name(s), - messages(std::set()) - { } - - //! copy constructor - Folder(const Folder& rhs); - - //! operator = - Folder& - operator = (const Folder& rhs); - - ~Folder(); //destructor - -private: - - void addMsg(Message* p_m); - void remMsg(Message* p_m); - - //! data members - std::string name; - std::set messages; -}; - -void swap(Folder& lhs, Folder& rhs); - -#endif // FOLDER_H diff --git a/ch13/ex13.49.50/main.cpp b/ch13/ex13.49.50/main.cpp deleted file mode 100644 index 0addc50f..00000000 --- a/ch13/ex13.49.50/main.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/*************************************************************************** - * @file main.cpp - * @author Alan.W - * @date 07--08 JAN 2014 - * @remark - ***************************************************************************/ -//! -//! Exercise 13.49: -//! Add a move constructor and move-assignment operator to your StrVec, String, -//! and Message classes. -//! -//! Exercise 13.50: -//! Put print statements in the move operations in your String class and rerun -//! the program from exercise 13.48 in § 13.6.1 (p. 534) that used a vector -//! to see when the copies are avoided. -// Dissucssion on SO: -// http://stackoverflow.com/questions/20967732/why-wasnt-the-move-constructor-called -//! - -#include "strvec.h" -#include "string.h" -#include "message.h" -#include "folder.h" -#include -#include - -int main() -{ - std::vector v; - String s; - for (unsigned i = 0; i != 4; ++i) - { - std::cout << v.capacity() << "\n"; - v.push_back(s); - } - - return 0; -} diff --git a/ch13/ex13.49.50/message.cpp b/ch13/ex13.49.50/message.cpp deleted file mode 100644 index cef5e4a7..00000000 --- a/ch13/ex13.49.50/message.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/*************************************************************************** - * @file message.cpp - * @author Alan.W - * @date 04 JAN 2014 - * @remark - ***************************************************************************/ - - -#include "message.h" -#include "folder.h" - -void Message::save(Folder &f) -{ - folders.insert(&f); - f.addMsg(this); -} - -void Message::remove(Folder &f) -{ - folders.erase(&f); - f.remMsg(this); -} - -void Message::addFld(Folder *f) -{ - folders.insert(f); -} - -void Message::remFld(Folder *f) -{ - folders.erase(f); -} - -void Message::move_Folders(Message *m) -{ - folders = std::move(m->folders); //use std::set move assignment - //! ^^^^^^^^^^~~~~~~~~~~^~ make it a rvalue reference. - - //! make folders pointing to the old message to point to 'this' one. - for(const auto &f : folders){ - f->remMsg(m); - f->addMsg(this); - } - - //! ensure that destroying m is harmless. - m->folders.clear(); -} - -void Message::add_to_Folders(const Message &m) -{ - for(auto &f : m.folders) - f->addMsg(this); -} - -void Message::remove_from_Folders() -{ - for(auto &f : folders) - f->remMsg(this); -} - -//! copy constructor -Message::Message(const Message &m): - contents(m.contents), folders(m.folders) -{ - add_to_Folders(m); -} - -//! move constructor -- 08.Jan.2014 -Message::Message(Message&& m): - contents(std::move(m.contents)) -{ - move_Folders(&m); -} - -//! destructor -Message::~Message() -{ - remove_from_Folders(); -} - -//! operator = -Message& -Message::operator =(const Message& rhs) -{ - remove_from_Folders(); - contents = rhs.contents; - folders = rhs.folders; - add_to_Folders(rhs); - - return *this; -} - -//! move assignment -- 08.Jan.2014 -Message & -Message::operator =(Message &&rhs) -{ - if(this != &rhs){ - remove_from_Folders(); - contents = std::move(rhs.contents); - //! ^^^^^^^^^^~~~~~~~~~~~~^~ move assignment - - //! reset the Folder to point to this message - move_Folders(&rhs); - } - - return *this; -} - - -void swap(Message &lhs, Message &rhs) -{ - using std::swap; // not strictly needed in this case, but good habit - // remove pointers to each Message from their (original) respective Folders - for (auto f: lhs.folders) - f->remMsg(&lhs); - for (auto f: rhs.folders) - f->remMsg(&rhs); - // swap the contents and Folder pointer sets - swap(lhs.folders, rhs.folders); // uses swap(set&, set&) - swap(lhs.contents, rhs.contents); // swap(string&, string&) - // add pointers to each Message to their (new) respective Folders - for (auto f: lhs.folders) - f->addMsg(&lhs); - for (auto f: rhs.folders) - f->addMsg(&rhs); -} diff --git a/ch13/ex13.49.50/message.h b/ch13/ex13.49.50/message.h deleted file mode 100644 index 55f20080..00000000 --- a/ch13/ex13.49.50/message.h +++ /dev/null @@ -1,68 +0,0 @@ -/*************************************************************************** - * @file message.h - * @author Alan.W - * @date 04 JAN 2014 - * @remark move operations added - * --08.Jan.2014 - ***************************************************************************/ -#ifndef MESSAGE_H -#define MESSAGE_H - -#include -#include - -class Folder; - -class Message -{ - friend class Folder; - friend void swap(Message& lhs, Message& rhs); - friend void swap(Folder& lhs, Folder& rhs); -public: - //! default constructor. - explicit Message( const std::string &str = ""): - contents(str){ } // folders is implicitly initialized to empty set - - //! copy constructor - Message(const Message& m); - - //! move constructor -- 08.Jan.2014 - Message(Message&& m); - - Message& - operator =(const Message& rhs); - - //! move assignment -- 08.Jan.2014 - Message& - operator =(Message&& rhs); - - //! destructor - ~Message(); - - //! public member functions - void save(Folder& f); - void remove(Folder& f); - - -private: - - //! for ex13.37 - void addFld(Folder *f); - void remFld(Folder *f); - - //! for ex13.49 08.Jan.2014 - void move_Folders(Message* m); - - - //! data members - std::string contents; // actual message text - std::set folders; // Folders that have this message - - //! utility functions - void add_to_Folders(const Message& m); - void remove_from_Folders(); -}; - -void swap(Message &lhs, Message &rhs); - -#endif // MESSAGE_H diff --git a/ch13/ex13.49.50/string.cpp b/ch13/ex13.49.50/string.cpp deleted file mode 100644 index 4ac8d848..00000000 --- a/ch13/ex13.49.50/string.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/*************************************************************************** - * @file string.cpp - * @author Alan.W - * @date 06 JAN 2014 - * @remark - ***************************************************************************/ - -#include "string.h" -#include -#include - -//! default constructor -String::String(): - elements (nullptr), - first_free (nullptr), - cap (nullptr) -{} - -//! constructor taking C-style string i.e. a char array terminated with'\0'. -String::String(const char * const c) -{ - auto p = c; - char* newData = alloc.allocate(sizeof(p)); - - std::uninitialized_copy(p, (p + sizeof(p)), newData); - - //! build the data structure - elements = newData; - cap = first_free = newData + sizeof(c); -} - -//! copy constructor -String::String(const String &s) -{ - char* newData = alloc.allocate(s.size()); - std::uninitialized_copy(s.begin(), s.end(), newData); - - //! build data structure - elements = newData; - cap = first_free = newData + s.size(); - - std::cout << "Copy constructing......\n"; -} - -//! move constructor -- 07.Jan.2014 -String::String(String &&s) noexcept : - elements(s.elements), first_free(s.first_free), cap(s.cap) -{ - s.elements = s.first_free = s.cap = nullptr; - - std::cout << "Move constructing......\n"; -} - -//! operator = 07 Jan 2014 -String &String::operator =(const String &rhs) -{ - //! allocate and copy first for protection against self-assignment - char* newData = alloc.allocate(rhs.size()); - std::uninitialized_copy(rhs.begin(), rhs.end(), newData); - - //! destroy and deallocate the lhs - free(); - - elements = newData; - cap = first_free = newData + rhs.size(); - - std::cout << "Assignmenting......\n"; - - return *this; -} - -//! move operator = 07 Jan 2014 -String &String::operator =(String &&rhs) noexcept -{ - if(this != &rhs) - { - free(); - - elements = rhs.elements; - first_free = rhs.first_free;//! operator = 07 Jan 2014 - cap = rhs.cap; - - rhs.elements = rhs.first_free = rhs.cap = nullptr; - } - - std::cout << "Move Assigning......\n"; - - return *this; -} - -//! destructor -String::~String() -{ - free(); -} - - - -//! destory and deallocate -void String::free() -{ - if(elements) - { - //! destroy all elements - std::for_each(&elements, &first_free, [&](const char* p){ - alloc.destroy(p); - }); - - alloc.deallocate(elements, cap - elements); - } -} diff --git a/ch13/ex13.49.50/string.h b/ch13/ex13.49.50/string.h deleted file mode 100644 index 10fce501..00000000 --- a/ch13/ex13.49.50/string.h +++ /dev/null @@ -1,70 +0,0 @@ -/*************************************************************************** - * @file string.h - * @author Alan.W - * @date 06 JAN 2014 - * @remark move constructor and move assignment added - * --07.Jan.2014 - ***************************************************************************/ - -#ifndef STRING_H -#define STRING_H - -#include - -/** - * @brief std::string like class without template - * - * design: - * - * [0][1][2][3][unconstructed chars][unallocated memory] - * ^ ^ ^ - * elements first_free cap - */ -class String -{ -public: - //! default constructor - String(); - - //! constructor taking C-style string i.e. a char array terminated with'\0'. - explicit String(const char * const c); - - //! copy constructor - explicit String(const String& s); - - //! move constructor --07.Jan.2014 - String(String&& s) noexcept; - - //! operator = - String& operator = (const String& rhs); - - //! move operator = --07.Jan.2014 - String& operator = (String&& rhs) noexcept; - - //! destructor - ~String(); - - //! members - char* begin() const { return elements; } - char* end() const { return first_free; } - - std::size_t size() const {return first_free - elements; } - std::size_t capacity() const {return cap - elements; } - - - -private: - - //! data members - char* elements; - char* first_free; - char* cap; - - std::allocator alloc; - - //! utillities for big 3 - void free(); - -}; - -#endif // STRING_H diff --git a/ch13/ex13.49.50/strvec.cpp b/ch13/ex13.49.50/strvec.cpp deleted file mode 100644 index fe02b6b3..00000000 --- a/ch13/ex13.49.50/strvec.cpp +++ /dev/null @@ -1,273 +0,0 @@ -/*************************************************************************** - * @file strvec.cpp - * @author Alan.W - * @date 05 JAN 2014 - * @remark move constructor and move assignment added - * --07 JAN 2014 - ***************************************************************************/ - -//! -//! Exercise 13.43: -//! Rewrite the free member to use for_each and a lambda (§ 10.3.2, p. 388) -//! in place of the for loop to destroy the elements. Which implementation do -//! you prefer, and why? -// The new version is better. Compared to the old one, it doesn't need to -// worry about the order and decrement.So more straightforward and handy. -// The only thing to do for using this approach is to add "&" to build the pointers -// to string pointers. -//! - -#include "strvec.h" -#include -#include - - -//! copy constructor -StrVec::StrVec(const StrVec &s) -{ - /** - * @brief newData is a pair of pointers pointing to newly allocated and copied - * range : [b, e) - */ - std::pair - newData = alloc_n_copy(s.begin(), s.end()); - - element = newData.first; - first_free = cap = newData.second; -} - -//! move constructor -- 07.Jan.2014 -StrVec::StrVec(StrVec &&s) noexcept : - element(s.element), first_free(s.first_free), cap(s.cap) -{ - s.element = s.first_free = s.cap = nullptr; -} - -/** - * @brief constructor taking initializer_list - * for ex 13.40 - * @param l - */ -StrVec::StrVec(std::initializer_list l) -{ - //! allocate memory as large as l.size() - std::string * const - newData = alloc.allocate(l.size()); - - //! copy elements from l to the address allocated - auto p = newData; - for(const auto &s : l) - alloc.construct(p++, s); - - //! build the data structure - element = newData; - first_free = cap = element + l.size(); -} - - -//! operator = -StrVec& -StrVec::operator =(const StrVec& rhs) -{ - //! allocate and copy first to protect against self-assignment - std::pair - newData = alloc_n_copy(rhs.begin(), rhs.end()); - - //! destroy and deallocate - free(); - - element = newData.first; - first_free = cap = newData.second; - - return *this; -} - - -//! move assignment 07.Jan.2014 -StrVec &StrVec::operator =(StrVec &&rhs) noexcept -{ - if (this != &rhs) - { - free(); - - element = rhs.element; - first_free = rhs.first_free; - cap = rhs.cap; - - //! leave the rhs in a destructible state - rhs.element = rhs.first_free = rhs.cap = nullptr; - } - - return *this; -} - -//! destructor -StrVec::~StrVec() -{ - free(); -} - -/** - * @brief allocate new room if nessary and push back the new string - * @param s new string - */ -void StrVec::push_back(const std::string& s) -{ - chk_n_alloc(); - alloc.construct(first_free++, s); -} - -/** - * @brief preallocate enough memory for specified number of elements - * @param n number of elements required - * @note this function is implemented refering to StrVec::reallocate(). - */ -void StrVec::reserve(std::size_t n) -{ - //! if the n is too small, just ignore it. - if(n <= capacity()) return; - - //! allocate and move old ones into the new address. - wy_alloc_n_move(n); -} - - -/** - * @brief Resizes to the specified number of elements. - * @param n Number of elements the %vector should contain. - * - * This function will resize it to the specified - * number of elements. If the number is smaller than the - * current size it is truncated, otherwise - * default constructed elements are appended. - */ - -void StrVec::resize(std::size_t n) -{ - resize(n,std::string()); -} - -/** - * @brief Resizes it to the specified number of elements. - * @param __new_size Number of elements it should contain. - * @param __x Data with which new elements should be populated. - * - * This function will resize it to the specified - * number of elements. If the number is smaller than the - * current size the it is truncated, otherwise - * the it is extended and new elements are populated with - * given data. - */ -void StrVec::resize(std::size_t n, const std::string &s) -{ - if(n < size()) - { - //! destroy the range : [element+n, first_free) using destructor - for(auto p = element + n; p != first_free; /* empty */) - alloc.destroy(p++); - - //! move frist_free point to the new address element + n - first_free = element + n; - } - else if( n > size() ) - { - for(auto i = size(); i != n; ++i) - push_back(std::string(s)); - } -} - -/** - * @brief Double the capacity and using std::move move the original strings to the newly - * allocated memory - */ -void StrVec::reallocate() -{ - //! calculate the new capacity required. - std::size_t newCapacity = size() ? 2 * size() : 1; - - //! allocate and move old ones into the new address. - wy_alloc_n_move(newCapacity); -} - -/** - * @brief allocate new space for the given range and copy them into it - * @param b - * @param e - * @return a pair of pointers pointing to [first element , one past the last) in the new space - */ -std::pair -StrVec::alloc_n_copy(std::string *b, std::string *e) -{ - //! calculate the size needed and allocate space accordingly - std::string* data = alloc.allocate(e - b); - - return { data, std::uninitialized_copy(b, e, data) }; - //! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - //! which copies the range [first,last) into the space of which - //! the starting address p_data is pointing to. - //! This function returns a pointer pointing to one past the last element. -} - -/** - * @brief destroy the elements and deallocate the space previously allocated. - */ -void StrVec::free() -{ - if(element) // if not nullptr - { - //! destory it in reverse order. - - /** @oldcode - * using for loop - * 05 JAN 2014 - * - for(auto p = first_free; p != element; ) - alloc.destroy(--p); //^^^^^ empty intentionally - */ - - - /** @newcode - * using std::for_each and a lambda - * 06 JAN 2014 - */ - std::for_each(&element,&first_free,[&](std::string* p){ - alloc.destroy(p); - }); - - - alloc.deallocate(element, capacity()); - } -} - -/** - * @brief allocate memory for spicified number of elements - * @param n - * @note it's user's responsibility to ensure that @param n is greater than - * the current capacity. - */ -void StrVec::wy_alloc_n_move(std::size_t n) -{ - std::size_t newCapacity = n; - - std::string* - newData = alloc.allocate(newCapacity); - - std::string* - dest = newData; - std::string* - elem = element; - - //! move the old to newly allocated space. - for(std::size_t i = 0; i != size(); ++i) - alloc.construct(dest++, std::move(*elem++)); - - free(); - - //! update data structure - element = newData; - first_free = dest; - cap = element + newCapacity; -} - - - diff --git a/ch13/ex13.49.50/strvec.h b/ch13/ex13.49.50/strvec.h deleted file mode 100644 index 1a46db2d..00000000 --- a/ch13/ex13.49.50/strvec.h +++ /dev/null @@ -1,80 +0,0 @@ -/*************************************************************************** - * @file strvec.h - * @author Alan.W - * @date 05 JAN 2014 - * @remark move constructor and move assignment added - * --07 JAN 2014 - ***************************************************************************/ - - -#ifndef STRVEC_H -#define STRVEC_H - -#include - -/** - * @brief The StrVec class a std::vector like class without template - * std:string is the only type it holds. - */ -class StrVec -{ -public: - //! Big 3/5. - StrVec(): - element(nullptr), first_free(nullptr), cap(nullptr) - {} - - StrVec(std::initializer_list l); - - explicit StrVec(const StrVec& s); - - explicit StrVec(StrVec&& s) noexcept; //! move constructor 07.Jan.2014 - - StrVec& - operator =(const StrVec& rhs); - - StrVec& - operator = (StrVec&& rhs) noexcept; //! move assignment 07.Jan.2014 - - ~StrVec(); - - //! public members - void push_back(const std::string &s); - - std::size_t size() const { return first_free - element; } - std::size_t capacity() const { return cap - element; } - - std::string* begin() const { return element; } - std::string* end() const { return first_free; } - - //! preallocate enough memory for specified number of elements - void reserve(std::size_t n); - - //! resize as required. - void resize(std::size_t n); - void resize(std::size_t n, const std::string& s); - -private: - - //! data members - std::string* element; // pointer to the first element - std::string* first_free; // pointer to the first free element - std::string* cap; // pointer to one past the end - - std::allocator alloc; - - //! utilities for Big 3/5 - void reallocate(); - void chk_n_alloc() { if (size() == capacity()) reallocate(); } - void free(); - - //! utilities added - //! used in reallocate() reserve() and resize(). - void wy_alloc_n_move(std::size_t n); - - std::pair - alloc_n_copy (std::string* b, std::string* e); - -}; - -#endif // STRVEC_H diff --git a/ch13/ex13.51.cpp b/ch13/ex13.51.cpp deleted file mode 100644 index d711f3ba..00000000 --- a/ch13/ex13.51.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/*************************************************************************** - * @file main.cpp - * @author Alan.W - * @date 9 Jan 2014 - * @remark This code is for the exercises from C++ Primer 5th Edition - * @note - ***************************************************************************/ -//! -//! Exercise 13.51: -//! Although unique_ptrs cannot be copied, in § 12.1.5 (p. 471) we wrote a clone -//! function that returned a unique_ptr by value. Explain why that function is -//! legal and how it works. -//! - -#include -#include -#include - -std::unique_ptr clone(int p) -{ - // ok: explicitly create a unique_ptr from int* - return std::unique_ptr(new int(p)); -} - -std::unique_ptr clone_ver2(int p) -{ - std::unique_ptr ret(new int (p)); - // . . . - return ret; -} -int main (){} -//! -// As it goes in the textbook, functions that return a nonreference type, along with -// the arithmetic, relational, bitwise, and postfix increment/decrement operators, all -// yield rvalues. Hence, the functions above return rvalue on which move constructor -// can be called on to steal the value inside. diff --git a/ch13/ex13.52.53/hasptr.cpp b/ch13/ex13.52.53/hasptr.cpp deleted file mode 100644 index f571296a..00000000 --- a/ch13/ex13.52.53/hasptr.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "hasptr.h" - -//! specific swap. -inline void -swap(HasPtr &lhs, HasPtr &rhs) -{ - using std::swap; - swap(lhs.ps, rhs.ps); // swap the pointers, not the string data - swap(lhs.i, rhs.i); // swap the int members - - std::cout <<"swapping!\n"; -} - -//! operator = using specific swap -HasPtr& -HasPtr::operator = (HasPtr rhs) -{ - swap(*this,rhs); - return *this; -} - -//! operator < overloading -inline bool -operator <(const HasPtr& lhs, const HasPtr& rhs) -{ - std::cout << " -#include -#include -#include - -//! revised for ex13.31 - -//! a class holding a std::string* -class HasPtr -{ - friend void swap(HasPtr&, HasPtr&); - friend bool operator <(const HasPtr& lhs, const HasPtr& rhs); -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) - { } - - //! move constructor. - HasPtr(HasPtr&& hp) noexcept : - ps(hp.ps), i(hp.i) - { hp.ps = nullptr; } - - - HasPtr& - operator = (HasPtr rhs); - //! ^^ no const here - - //! destructor. - ~HasPtr() - { - delete ps; - } - -private: - std::string *ps; - int i; -}; -#endif // HASPTR_H diff --git a/ch13/ex13.52.53/main.cpp b/ch13/ex13.52.53/main.cpp deleted file mode 100644 index a84f143c..00000000 --- a/ch13/ex13.52.53/main.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/*************************************************************************** - * @file main.cpp - * @author Alan.W - * @date 9 Jan 2014 - * @remark This code is for the exercises from C++ Primer 5th Edition - * @note - ***************************************************************************/ -//! -//! Exercise 13.52: -//! Explain in detail what happens in the assignments of the HasPtr objects on -//! page 541. In particular, describe step by step what happens to values of hp, -//! hp2, and of the rhs parameter in the HasPtr assignment operator. -//! -//! Exercise 13.53: -//! As a matter of low-level efficiency, the HasPtr assignment operator is not -//! ideal. Explain why. Implement a copy-assignment and move-assignment operator -//! for HasPtr and compare the operations executed in your new move-assignment -//! operator versus the copy-and-swap version. -// Discussing on SO: -// http://stackoverflow.com/questions/21010371/why-is-it-not-efficient-to-use-a-single-assignment-operator-handling-both-copy-a -//! - -#include "hasptr.h" -#include -#include - -int main() -{ - //! default constructors are called to construct object hp and hp2 - HasPtr hp("This is hp!\n"); - HasPtr hp2("This is hp2\n"); - - - - hp = std::move(hp2); - /** - * 1 call std::move to convert hp2 to a rvalue. - * 2 Both copy and move constructors are viable, but move constructor a better - * match.Hence move constructor is called constructing the parameter rhs. - * ^^^^~~~~~~~~~~~~ ~~~~~~~~~~~~~~^^^ - * 3 assignment operator =() is called - * 4 the specific swap is called - * 5 inside the specific swap(), the std::string* ps and int i are swaped. - * 6 after swapping, the new *this is returned from the function - * HasPtr& HasPtr::operator = (HasPtr rhs) - * 7 At the end, desructor is called to destroy all object. - */ - - - return 0; -} - - diff --git a/ch13/ex13.55/Alan.h b/ch13/ex13.55/Alan.h deleted file mode 100644 index b9e4f785..00000000 --- a/ch13/ex13.55/Alan.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef ALAN_H -#define ALAN_H - -#include -#include - -void alan(const std::string &s = "") -{ - std::cout << "\033[1;32m@Alan:" - << s - << "\033[0m" - << std::endl; -} - -#endif // ALAN_H diff --git a/ch13/ex13.55/StrBlob.h b/ch13/ex13.55/StrBlob.h deleted file mode 100644 index 6cbb76cd..00000000 --- a/ch13/ex13.55/StrBlob.h +++ /dev/null @@ -1,202 +0,0 @@ -/*************************************************************************** - * @file main.cpp - * @author Alan.W - * @date 01 JAN 2014 - * @remark 10 JAN 2014 : Rvalue reference version push_back added - ***************************************************************************/ -//! -//! 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 -#include "Alan.h" - -// 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 );} //copy version - void push_back( std::string&&t) { data->push_back(std::move(t));} //move version - - 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.55/main.cpp b/ch13/ex13.55/main.cpp deleted file mode 100644 index 54baf380..00000000 --- a/ch13/ex13.55/main.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/*************************************************************************** - * @file main.cpp - * @author Alan.W - * @date 10 Jan 2014 - * @remark This code is for the exercises from C++ Primer 5th Edition - * @note - ***************************************************************************/ -//! -//! Exercise 13.55: -//! Add an rvalue reference version of push_back to your StrBlob. -//! - -#include -#include -#include -#include -#include "StrBlob.h" - -int main() -{ - StrBlob s; - s.push_back(std::string()); - - - return 0; -} - - diff --git a/ch13/ex13.56.57.58/Alan.h b/ch13/ex13.56.57.58/Alan.h deleted file mode 100644 index e42ca7c2..00000000 --- a/ch13/ex13.56.57.58/Alan.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef ALAN_H -#define ALAN_H - -#include -#include - -void alan(const std::string &s = "") -{ - std::cout << "\033[1;32m@Alan:" - << s - << "\033[0m"; -} - -#endif // ALAN_H diff --git a/ch13/ex13.56.57.58/StrBlob.h b/ch13/ex13.56.57.58/StrBlob.h deleted file mode 100644 index 6cbb76cd..00000000 --- a/ch13/ex13.56.57.58/StrBlob.h +++ /dev/null @@ -1,202 +0,0 @@ -/*************************************************************************** - * @file main.cpp - * @author Alan.W - * @date 01 JAN 2014 - * @remark 10 JAN 2014 : Rvalue reference version push_back added - ***************************************************************************/ -//! -//! 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 -#include "Alan.h" - -// 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 );} //copy version - void push_back( std::string&&t) { data->push_back(std::move(t));} //move version - - 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.56.57.58/main.cpp b/ch13/ex13.56.57.58/main.cpp deleted file mode 100644 index 28143bbd..00000000 --- a/ch13/ex13.56.57.58/main.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/*************************************************************************** - * @file main.cpp - * @author Alan.W - * @date 10 Jan 2014 - * @remark This code is for the exercises from C++ Primer 5th Edition - * @note - ***************************************************************************/ -//! -//! Exercise 13.56: What would happen if we defined sorted as: -/* - Foo Foo::sorted() const & - { - Foo ret(*this); - return ret.sorted(); - } -*/// recursion and stack overflow? -- correct! -//! -//! Exercise 13.57: What if we defined sorted as: - -// Foo Foo::sorted() const & -// { return Foo(*this).sorted(); } -//! This version works, as it will call the move verion which can return control -//! to the caller. -//! -//! Exercise 13.58: Write versions of class Foo with print statements in their -//! sorted functions to test your answers to the previous two exercises. -//! -#include -#include -#include - -class Foo -{ -public: - Foo sorted() &&; // may run on modifiable rvalues - Foo sorted() const &; // may run on any kind of Foo -private: - std::vector data; -}; - -//! infinit recursion -/* -Foo Foo::sorted() const & -{ - Foo ret(*this); - return ret.sorted(); -} -*/ - -Foo Foo::sorted() && -{ - std::sort(data.begin(), data.end()); - std::cout << "Rvalue version\n"; - return *this; -} -Foo Foo::sorted() const & -{ - std::cout << "Lvalue version\n"; - return Foo(*this).sorted(); -} - -int main() -{ - Foo foo; - foo.sorted(); - std::cout << "exit\n"; - return 0; -} -//! output -//Lvalue version -//Rvalue version -//exit diff --git a/ch13/ex13_49_Message.cpp b/ch13/ex13_49_Message.cpp new file mode 100644 index 00000000..3708c627 --- /dev/null +++ b/ch13/ex13_49_Message.cpp @@ -0,0 +1,167 @@ +#include "ex13_49_Message.h" +#include + +void swap(Message &lhs, Message &rhs) +{ + using std::swap; + for (auto f : lhs.folders) + f->remMsg(&lhs); + std::cout << "Remove message from folders" << std::endl; // debug + + for (auto f : rhs.folders) + f->remMsg(&rhs); + std::cout << "Remove message from folders" << std::endl; // debug + + swap(lhs.folders, rhs.folders); + swap(lhs.contents, rhs.contents); + + std::cout << "Message members swaped" << std::endl; // debug + + for (auto f : lhs.folders) + f->addMsg(&lhs); + std::cout << "Added message to folders" << std::endl; // debug + + for (auto f : rhs.folders) + f->addMsg(&rhs); + std::cout << "Added message to folders" << std::endl; // debug +} + +Message::Message(const Message &m) : contents(m.contents), folders(m.folders) +{ + add_to_Folders(m); +} + +Message::~Message() +{ + remove_from_Folders(); +} + +void Message::save(Folder &f) +{ + folders.insert(&f); + f.addMsg(this); +} + +void Message::remove(Folder &f) +{ + folders.erase(&f); + f.remMsg(this); +} + +void Message::add_to_Folders(const Message &m) +{ + for (auto f : m.folders) + f->addMsg(this); + std::cout << "Added message to folders" << std::endl; // debug +} + +void Message::remove_from_Folders() +{ + for (auto f : folders) + f->remMsg(this); + std::cout << "Remove message from folders" << std::endl; // debug +} + +Message& Message::operator=(const Message &rhs) +{ + remove_from_Folders(); + contents = rhs.contents; + folders = rhs.folders; + std::cout << "Message members assgined" << std::endl; // debug + add_to_Folders(rhs); + return *this; +} + +void Message::print_debug() +{ + std::cout << contents << ": "; + for (auto f : folders) + std::cout << f->fldr() << " "; + std::cout << std::endl; +} + +Message& Message::operator = (Message &&rhs) NOEXCEPT +{ + remove_from_Folders(); + contents = std::move(rhs.contents); + folders = std::move(rhs.folders); + std::cout << "Message members moved" << std::endl; // debug + return *this; +} + +// Folder Implementation + +void swap(Folder &lhs, Folder &rhs) +{ + using std::swap; + for (auto m : lhs.msgs) + m->remFldr(&lhs); + std::cout << "clear folder" << std::endl; // debug + + for (auto m : rhs.msgs) + m->remFldr(&rhs); + std::cout << "clear folder" << std::endl; // debug + + swap(lhs.name, rhs.name); + swap(lhs.msgs, rhs.msgs); + std::cout << "Folder members swaped" << std::endl; // debug + + for (auto m : lhs.msgs) + m->addFldr(&lhs); + std::cout << "Added messages to folder" << std::endl; // debug + + for (auto m : rhs.msgs) + m->addFldr(&rhs); + std::cout << "Added messages to folder" << std::endl; // debug +} + +void Folder::add_to_Message(const Folder &f) +{ + for (auto m : f.msgs) + m->addFldr(this); + std::cout << "Added messages to folder" << std::endl; // debug +} + +Folder::Folder(const Folder &f) : name(f.name), msgs(f.msgs) +{ + add_to_Message(f); +} + +void Folder::remove_from_Message() +{ + for (auto m : msgs) + m->remFldr(this); + std::cout << "clear folder" << std::endl; // debug +} + +Folder::~Folder() +{ + remove_from_Message(); +} + +Folder& Folder::operator =(const Folder &rhs) +{ + remove_from_Message(); + name = rhs.name; + msgs = rhs.msgs; + std::cout << "Folder members assigned" << std::endl; // debug + add_to_Message(rhs); + return *this; +} + +void Folder::print_debug() +{ + std::cout << name << ": "; + for (auto m : msgs) + std::cout << m->msg() << " "; + std::cout << std::endl; +} + +Folder& Folder::operator=(Folder &&rhs) NOEXCEPT +{ + remove_from_Message(); + name = std::move(rhs.name); + msgs = std::move(rhs.msgs); + std::cout << "Folder members moved" << std::endl; // debug + return *this; +} diff --git a/ch13/ex13_49_Message.h b/ch13/ex13_49_Message.h new file mode 100644 index 00000000..06523654 --- /dev/null +++ b/ch13/ex13_49_Message.h @@ -0,0 +1,77 @@ +#ifndef CP5_MESSAGE_H_ +#define CP5_MESSAGE_H_ + +#include +#include + +#ifndef _MSC_VER +#define NOEXCEPT noexcept +#else +#define NOEXCEPT +#endif + +class Folder; + +class Message +{ + friend void swap(Message &, Message &); + friend void swap(Folder &, Folder &); + friend class Folder; +public: + explicit Message(const std::string &str = "") : contents(str) {} + Message(const Message&); + Message& operator=(const Message&); + Message(Message &&m) NOEXCEPT : contents(std::move(m.contents)), folders(std::move(m.folders)) {} + Message& operator=(Message&&) NOEXCEPT; + ~Message(); + + void save(Folder&); + void remove(Folder&); + + const std::string& msg() const { return contents; } + void print_debug(); + +private: + void add_to_Folders(const Message&); + void remove_from_Folders(); + + void addFldr(Folder *f) { folders.insert(f); } + void remFldr(Folder *f) { folders.erase(f); } + +private: + std::string contents; + std::set folders; +}; + +void swap(Message&, Message&); + +class Folder { + friend void swap(Message&, Message&); + friend void swap(Folder &, Folder &); + friend class Message; +public: + explicit Folder(const std::string &str = "") :name(str) {} + Folder(const Folder &); + Folder& operator=(const Folder &); + Folder(Folder &&f) NOEXCEPT : name(std::move(f.name)), msgs(std::move(f.msgs)) {} + Folder& operator=(Folder &&) NOEXCEPT; + ~Folder(); + + const std::string& fldr() const { return name; } + void print_debug(); + +private: + std::string name; + std::set msgs; + + void add_to_Message(const Folder&); + void remove_from_Message(); + + void addMsg(Message *m) { msgs.insert(m); } + void remMsg(Message *m) { msgs.erase(m); } +}; + +void swap(Folder &, Folder &); + +#endif + diff --git a/ch13/ex13_49_StrVec.cpp b/ch13/ex13_49_StrVec.cpp new file mode 100644 index 00000000..1b4c879f --- /dev/null +++ b/ch13/ex13_49_StrVec.cpp @@ -0,0 +1,115 @@ +#include "ex13_49_StrVec.h" +#include // for_each + +void StrVec::push_back(const std::string &s) +{ + chk_n_alloc(); + alloc.construct(first_free++, s); +} + +std::pair +StrVec::alloc_n_copy(const std::string *b, const std::string *e) +{ + auto data = alloc.allocate(e-b); + return { data, std::uninitialized_copy(b, e, data) }; +} + +void StrVec::free() +{ + if (elements) { + for_each(elements, first_free, [this](std::string &rhs){ alloc.destroy(&rhs); }); + alloc.deallocate(elements, cap - elements); + } +} + +void StrVec::range_initialize(const std::string *first, const std::string *last) +{ + auto newdata = alloc_n_copy(first, last); + elements = newdata.first; + first_free = cap = newdata.second; +} + +StrVec::StrVec(const StrVec &rhs) +{ + range_initialize(rhs.begin(), rhs.end()); +} + +StrVec::StrVec(std::initializer_list il) +{ + range_initialize(il.begin(), il.end()); +} + +StrVec::~StrVec() +{ + free(); +} + +StrVec& StrVec::operator = (const StrVec &rhs) +{ + auto data = alloc_n_copy(rhs.begin(), rhs.end()); + free(); + elements = data.first; + first_free = cap = data.second; + return *this; +} + +void StrVec::alloc_n_move(size_t new_cap) +{ + auto newdata = alloc.allocate(new_cap); + auto dest = newdata; + auto elem = elements; + for (size_t i = 0; i != size(); ++i) + alloc.construct(dest++, std::move(*elem++)); + free(); + elements = newdata; + first_free = dest; + cap = elements + new_cap; +} + +void StrVec::reallocate() +{ + auto newcapacity = size() ? 2 * size() : 1; + alloc_n_move(newcapacity); +} + +void StrVec::reserve(size_t new_cap) +{ + if (new_cap <= capacity()) return; + alloc_n_move(new_cap); +} + +void StrVec::resize(size_t count) +{ + resize(count, std::string()); +} + +void StrVec::resize(size_t count, const std::string &s) +{ + if (count > size()) { + if (count > capacity()) reserve(count * 2); + for (size_t i = size(); i != count; ++i) + alloc.construct(first_free++, s); + } + else if (count < size()) { + while (first_free != elements + count) + alloc.destroy(--first_free); + } +} + +StrVec::StrVec(StrVec &&s) NOEXCEPT : elements(s.elements), first_free(s.first_free), cap(s.cap) +{ + // leave s in a state in which it is safe to run the destructor. + s.elements = s.first_free = s.cap = nullptr; +} + +StrVec& StrVec::operator = (StrVec &&rhs) NOEXCEPT +{ + if (this != &rhs) { + free(); + elements = rhs.elements; + first_free = rhs.first_free; + cap = rhs.cap; + rhs.elements = rhs.first_free = rhs.cap = nullptr; + } + return *this; +} diff --git a/ch13/ex13_49_StrVec.h b/ch13/ex13_49_StrVec.h new file mode 100644 index 00000000..bc698642 --- /dev/null +++ b/ch13/ex13_49_StrVec.h @@ -0,0 +1,54 @@ +#ifndef CP5_STRVEC_H_ +#define CP5_STRVEC_H_ + +#include +#include +#include + +#ifndef _MSC_VER +#define NOEXCEPT noexcept +#else +#define NOEXCEPT +#endif + +class StrVec +{ +public: + StrVec() : elements(nullptr), first_free(nullptr), cap(nullptr) {} + StrVec(std::initializer_list); + StrVec(const StrVec&); + StrVec& operator=(const StrVec&); + StrVec(StrVec&&) NOEXCEPT; + StrVec& operator=(StrVec&&) NOEXCEPT; + ~StrVec(); + + void push_back(const std::string&); + size_t size() const { return first_free - elements; } + size_t capacity() const { return cap - elements; } + std::string *begin() const { return elements; } + std::string *end() const { return first_free; } + + std::string& at(size_t pos) { return *(elements + pos); } + const std::string& at(size_t pos) const { return *(elements + pos); } + + void reserve(size_t new_cap); + void resize(size_t count); + void resize(size_t count, const std::string&); + +private: + std::pair alloc_n_copy(const std::string*, const std::string*); + void free(); + void chk_n_alloc() { if (size() == capacity()) reallocate(); } + void reallocate(); + void alloc_n_move(size_t new_cap); + void range_initialize(const std::string*, const std::string*); + +private: + std::string *elements; + std::string *first_free; + std::string *cap; + std::allocator alloc; +}; + +#endif + diff --git a/ch13/ex13_49_String.cpp b/ch13/ex13_49_String.cpp new file mode 100644 index 00000000..10a908ac --- /dev/null +++ b/ch13/ex13_49_String.cpp @@ -0,0 +1,67 @@ +#include "ex13_49_String.h" +#include + +std::pair +String::alloc_n_copy(const char *b, const char *e) +{ + auto str = alloc.allocate(e-b); + return{ str, std::uninitialized_copy(b, e, str)}; +} + +void String::range_initializer(const char *first, const char *last) +{ + auto newstr = alloc_n_copy(first, last); + elements = newstr.first; + end = newstr.second; +} + +String::String(const char *s) +{ + char *sl = const_cast(s); + while (*sl) + ++sl; + range_initializer(s, ++sl); +} + +String::String(const String& rhs) +{ + range_initializer(rhs.elements, rhs.end); +} + +void String::free() +{ + if (elements) { + std::for_each(elements, end, [this](char &c){ alloc.destroy(&c); }); + alloc.deallocate(elements, end - elements); + } +} + +String::~String() +{ + free(); +} + +String& String::operator = (const String &rhs) +{ + auto newstr = alloc_n_copy(rhs.elements, rhs.end); + free(); + elements = newstr.first; + end = newstr.second; + return *this; +} + +String::String(String &&s) NOEXCEPT : elements(s.elements), end(s.end) +{ + s.elements = s.end = nullptr; +} + +String& String::operator = (String &&rhs) NOEXCEPT +{ + if (this != &rhs) { + free(); + elements = rhs.elements; + end = rhs.end; + rhs.elements = rhs.end = nullptr; + } + return *this; +} diff --git a/ch13/ex13_49_String.h b/ch13/ex13_49_String.h new file mode 100644 index 00000000..6d40cd0b --- /dev/null +++ b/ch13/ex13_49_String.h @@ -0,0 +1,39 @@ +#ifndef CP5_STRING_H__ +#define CP5_STRING_H__ + +#include + +#ifndef _MSC_VER +#define NOEXCEPT noexcept +#else +#define NOEXCEPT +#endif + +class String +{ +public: + String() : String("") {} + String(const char *); + String(const String&); + String& operator=(const String&); + String(String &&) NOEXCEPT; + String& operator=(String&&) NOEXCEPT; + ~String(); + + const char *c_str() const { return elements; } + size_t size() const { return end - elements; } + size_t length() const { return end - elements - 1; } + +private: + std::pair alloc_n_copy(const char*, const char*); + void range_initializer(const char*, const char*); + void free(); + +private: + char *elements; + char *end; + std::allocator alloc; +}; + +#endif + diff --git a/ch13/ex13_53.cpp b/ch13/ex13_53.cpp new file mode 100644 index 00000000..09a55cfc --- /dev/null +++ b/ch13/ex13_53.cpp @@ -0,0 +1,60 @@ +#include "ex13_53.h" +#include + +inline void swap(HasPtr &lhs, HasPtr &rhs) +{ + using std::swap; + swap(lhs.ps, rhs.ps); + swap(lhs.i, rhs.i); + std::cout << "call swap" << std::endl; +} + +HasPtr::HasPtr(const std::string &s) : ps(new std::string(s)), i(0) +{ + std::cout << "call constructor" << std::endl; +} + +HasPtr::HasPtr(const HasPtr &hp) : ps(new std::string(*hp.ps)), i(hp.i) +{ + std::cout << "call copy constructor" << std::endl; +} + +HasPtr::HasPtr(HasPtr &&p) noexcept : ps(p.ps), i(p.i) +{ + p.ps = 0; + std::cout << "call move constructor" << std::endl; +} + +HasPtr& HasPtr::operator=(HasPtr rhs) +{ + swap(*this, rhs); + return *this; +} + +//HasPtr& HasPtr::operator=(const HasPtr &rhs) +//{ +// auto newp = new std::string(*rhs.ps); +// delete ps; +// ps = newp; +// i = rhs.i; +// std::cout << "call copy assignment" << std::endl; +// return *this; +//} + +//HasPtr& HasPtr::operator=(HasPtr &&rhs) noexcept +//{ +// if (this != &rhs) +// { +// delete ps; +// ps = rhs.ps; +// i = rhs.i; +// std::cout << "call move assignment" << std::endl; +// } +// return *this; +//} + +HasPtr::~HasPtr() +{ + std::cout << "call destructor" << std::endl; + delete ps; +} diff --git a/ch13/ex13_53.h b/ch13/ex13_53.h new file mode 100644 index 00000000..315c5fce --- /dev/null +++ b/ch13/ex13_53.h @@ -0,0 +1,22 @@ +#ifndef CP5_ex13_53_h +#define CP5_ex13_53_h + +#include + +class HasPtr { +public: + friend void swap(HasPtr&, HasPtr&); + HasPtr(const std::string &s = std::string()); + HasPtr(const HasPtr &hp); + HasPtr(HasPtr &&p) noexcept; + HasPtr& operator=(HasPtr rhs); + //HasPtr& operator=(const HasPtr &rhs); + //HasPtr& operator=(HasPtr &&rhs) noexcept; + ~HasPtr(); + +private: + std::string *ps; + int i; +}; + +#endif // CP5_ex13_53_h diff --git a/ch13/ex13_53_test.cpp b/ch13/ex13_53_test.cpp new file mode 100644 index 00000000..57fea60b --- /dev/null +++ b/ch13/ex13_53_test.cpp @@ -0,0 +1,32 @@ +#include "ex13_53.h" + +int main() +{ + HasPtr hp1("hello"), hp2("World"), *pH = new HasPtr("World"); + hp1 = hp2; + hp1 = std::move(*pH); +} + +// when used copy-and-swap + +//call constructor +//call constructor +//call constructor +//call copy constructor !!! +//call swap !!! +//call destructor !!! +//call move constructor !!! +//call swap !!! +//call destructor !!! +//call destructor +//call destructor + +// when used two assignment operator. + +//call constructor +//call constructor +//call constructor +//call copy assignment !!! +//call move assignment !!! +//call destructor +//call destructor diff --git a/ch13/ex13_58.cpp b/ch13/ex13_58.cpp new file mode 100644 index 00000000..7762f27c --- /dev/null +++ b/ch13/ex13_58.cpp @@ -0,0 +1,40 @@ +#include +#include +#include + +using std::vector; using std::sort; + +class Foo { +public: + Foo sorted() &&; + Foo sorted() const &; +private: + vector data; +}; + +Foo Foo::sorted() && { + sort(data.begin(), data.end()); + std::cout << "&&" << std::endl; // debug + return *this; +} + +Foo Foo::sorted() const & { +// Foo ret(*this); +// sort(ret.data.begin(), ret.data.end()); +// return ret; + + std::cout << "const &" << std::endl; // debug + +// Foo ret(*this); +// ret.sorted(); // Exercise 13.56 +// return ret; + + return Foo(*this).sorted(); // Exercise 13.57 +} + +int main() +{ + Foo().sorted(); // call "&&" + Foo f; + f.sorted(); // call "const &" +}