> 文章列表 > C++ Primer第五版_第十三章习题答案(31~40)

C++ Primer第五版_第十三章习题答案(31~40)

C++ Primer第五版_第十三章习题答案(31~40)

文章目录

      • 练习13.31
      • 练习13.32
      • 练习13.23
      • 练习13.34
      • 练习13.35
      • 练习13.36
        • 头文件
        • CPP文件
      • 练习13.37
        • 头文件
        • CPP文件
      • 练习13.38
      • 练习13.39
        • 头文件
        • CPP文件
      • 练习13.40
        • 头文件
        • CPP文件

练习13.31

为你的 HasPtr 类定义一个 < 运算符,并定义一个 HasPtr 的 vector。为这个 vector 添加一些元素,并对它执行 sort。注意何时会调用 swap。

#ifndef CP5_ex13_31_h
#define CP5_ex13_31_h#include <string>
#include <iostream>class HasPtr
{
public:friend void swap(HasPtr&, HasPtr&);friend bool operator<(const HasPtr &lhs, const HasPtr &rhs);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=(HasPtr tmp){this->swap(tmp);return *this;}~HasPtr(){delete ps;}void swap(HasPtr &rhs){using std::swap;swap(ps, rhs.ps);swap(i, rhs.i);std::cout << "call swap(HasPtr &rhs)" << std::endl;}void show() const{std::cout << *ps << std::endl;}
private:std::string *ps;int i;
};void swap(HasPtr& lhs, HasPtr& rhs)
{lhs.swap(rhs);
}bool operator<(const HasPtr &lhs, const HasPtr &rhs)
{return *lhs.ps < *rhs.ps;
}#endif

练习13.32

指针的 HasPtr 版本会从 swap 函数收益吗?如果会,得到了什么益处?如果不是,为什么?

不会。类值的版本利用swap交换指针不用进行内存分配,因此得到了性能上的提升。类指针的版本本来就不用进行内存分配,所以不会得到性能提升。

练习13.23

为什么Message的成员save和remove的参数是一个 Folder&?为什么我们不能将参数定义为 Folder 或是 const Folder?

因为 save 和 remove 操作需要更新指定 Folder。

练习13.34

编写本节所描述的 Message。

头文件

#ifndef ex13_34_h
#define ex13_34_h#include <string>
#include <set>class Folder;class Message
{friend void swap(Message &, Message &);friend void swap(Folder &, Folder &);friend class Folder;
public:explicit Message(const std::string& s = "") :contents(s) {}Message(const Message&);Message& operator=(const Message&);~Message();void save(Folder&);void remove(Folder&);void print_debug();private:std::string contents;std::set<Folder*> folders;void add_to_Folders(const Message&);void remove_from_Folders();void addFldr(Folder* f) { folders.insert(f); }void remFlddr(Folder* f) { folders.erase(f); }
};void swap(Message&, Message&);class Folder
{friend void swap(Message&, Message&);friend void swap(Folder&, Folder&);friend class Message;
public:Folder() = default;Folder(const Folder&);Folder& operator=(const Folder&);~Folder();void print_debug();private:std::set<Message*> msgs;void add_to_Message(const Folder&);void remove_to_Message();void addMsg(Message* m) { msgs.insert(m); }void remMsg(Message *m) { msgs.erase(m); }
};void swap(Folder&, Folder&);#endif // !ex13_34_h

CPP文件

#include "exercise13_34.h"
#include <iostream>void swap(Message& lhs, Message& rhs)
{using std::swap;for (auto f : lhs.folders)f->remMsg(&lhs);for (auto f : rhs.folders)f->remMsg(&rhs);swap(lhs.folders, rhs.folders);swap(lhs.contents, rhs.contents);for (auto f : lhs.folders)f->addMsg(&lhs);for (auto f : rhs.folders)f->addMsg(&rhs);
}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);
}Message::Message(const Message& m) :contents(m.contents), folders(m.folders)
{add_to_Folders(m);
}void Message::remove_from_Folders()
{for (auto f : folders)f->remMsg(this);folders.clear();
}Message::~Message()
{remove_from_Folders();
}Message& Message::operator=(const Message& rhs)
{remove_from_Folders();contents = rhs.contents;folders = rhs.folders;add_to_Folders(rhs);return *this;
}void Message::print_debug()
{std::cout << contents << std::endl;
}void swap(Folder& lhs, Folder& rhs)
{using std::swap;for (auto m : lhs.msgs)m->remFlddr(&lhs);for (auto m : rhs.msgs)m->remFlddr(&rhs);swap(lhs.msgs, rhs.msgs);for (auto m : lhs.msgs)m->addFldr(&lhs);for (auto m : rhs.msgs)m->addFldr(&rhs);
}void Folder::add_to_Message(const Folder& f)
{for (auto m : f.msgs)m->addFldr(this);
}Folder::Folder(const Folder& f) :msgs(f.msgs)
{add_to_Message(f);
}void Folder::remove_to_Message()
{for (auto m : msgs)m->remFlddr(this);msgs.clear();
}Folder::~Folder()
{remove_to_Message();
}Folder& Folder::operator=(const Folder& rhs)
{remove_to_Message(); msgs = rhs.msgs;add_to_Message(rhs);return *this;
}void Folder::print_debug()
{for (auto m : msgs)std::cout << m->contents << " ";std::cout << std::endl;
}

练习13.35

如果Message 使用合成的拷贝控制成员,将会发生什么?

在赋值后一些已存在的 Folders 将会与 Message 不同步。拷贝构造函数和拷贝赋值运算符要重新动态分配内存。因为 StrBlob 使用的是智能指针,当引用计数为0时会自动释放对象,因此不需要析构函数。

练习13.36

设计并实现对应的 Folder 类。此类应该保存一个指向 Folder 中包含 Message 的 set。

头文件

#ifndef ex13_34_h
#define ex13_34_h#include <string>
#include <set>class Folder;class Message
{friend void swap(Message &, Message &);friend void swap(Folder &, Folder &);friend class Folder;
public:explicit Message(const std::string& s = "") :contents(s) {}Message(const Message&);Message& operator=(const Message&);~Message();void save(Folder&);void remove(Folder&);void print_debug();private:std::string contents;std::set<Folder*> folders;void add_to_Folders(const Message&);void remove_from_Folders();void addFldr(Folder* f) { folders.insert(f); }void remFlddr(Folder* f) { folders.erase(f); }
};void swap(Message&, Message&);class Folder
{friend void swap(Message&, Message&);friend void swap(Folder&, Folder&);friend class Message;
public:Folder() = default;Folder(const Folder&);Folder& operator=(const Folder&);~Folder();void print_debug();private:std::set<Message*> msgs;void add_to_Message(const Folder&);void remove_to_Message();void addMsg(Message* m) { msgs.insert(m); }void remMsg(Message *m) { msgs.erase(m); }
};void swap(Folder&, Folder&);#endif // !ex13_34_h

CPP文件

#include "exercise13_34.h"
#include <iostream>void swap(Message& lhs, Message& rhs)
{using std::swap;for (auto f : lhs.folders)f->remMsg(&lhs);for (auto f : rhs.folders)f->remMsg(&rhs);swap(lhs.folders, rhs.folders);swap(lhs.contents, rhs.contents);for (auto f : lhs.folders)f->addMsg(&lhs);for (auto f : rhs.folders)f->addMsg(&rhs);
}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);
}Message::Message(const Message& m) :contents(m.contents), folders(m.folders)
{add_to_Folders(m);
}void Message::remove_from_Folders()
{for (auto f : folders)f->remMsg(this);folders.clear();
}Message::~Message()
{remove_from_Folders();
}Message& Message::operator=(const Message& rhs)
{remove_from_Folders();contents = rhs.contents;folders = rhs.folders;add_to_Folders(rhs);return *this;
}void Message::print_debug()
{std::cout << contents << std::endl;
}void swap(Folder& lhs, Folder& rhs)
{using std::swap;for (auto m : lhs.msgs)m->remFlddr(&lhs);for (auto m : rhs.msgs)m->remFlddr(&rhs);swap(lhs.msgs, rhs.msgs);for (auto m : lhs.msgs)m->addFldr(&lhs);for (auto m : rhs.msgs)m->addFldr(&rhs);
}void Folder::add_to_Message(const Folder& f)
{for (auto m : f.msgs)m->addFldr(this);
}Folder::Folder(const Folder& f) :msgs(f.msgs)
{add_to_Message(f);
}void Folder::remove_to_Message()
{for (auto m : msgs)m->remFlddr(this);msgs.clear();
}Folder::~Folder()
{remove_to_Message();
}Folder& Folder::operator=(const Folder& rhs)
{remove_to_Message(); msgs = rhs.msgs;add_to_Message(rhs);return *this;
}void Folder::print_debug()
{for (auto m : msgs)std::cout << m->contents << " ";std::cout << std::endl;
}

练习13.37

为 Message 类添加成员,实现向 folders 添加和删除一个给定的 Folder*。这两个成员类似Folder 类的 addMsg 和 remMsg 操作。

头文件

#ifndef ex13_34_h
#define ex13_34_h#include <string>
#include <set>class Folder;class Message
{friend void swap(Message &, Message &);friend void swap(Folder &, Folder &);friend class Folder;
public:explicit Message(const std::string& s = "") :contents(s) {}Message(const Message&);Message& operator=(const Message&);~Message();void save(Folder&);void remove(Folder&);void print_debug();private:std::string contents;std::set<Folder*> folders;void add_to_Folders(const Message&);void remove_from_Folders();void addFldr(Folder* f) { folders.insert(f); }void remFlddr(Folder* f) { folders.erase(f); }
};void swap(Message&, Message&);class Folder
{friend void swap(Message&, Message&);friend void swap(Folder&, Folder&);friend class Message;
public:Folder() = default;Folder(const Folder&);Folder& operator=(const Folder&);~Folder();void print_debug();private:std::set<Message*> msgs;void add_to_Message(const Folder&);void remove_to_Message();void addMsg(Message* m) { msgs.insert(m); }void remMsg(Message *m) { msgs.erase(m); }
};void swap(Folder&, Folder&);#endif // !ex13_34_h

CPP文件

#include "exercise13_34.h"
#include <iostream>void swap(Message& lhs, Message& rhs)
{using std::swap;for (auto f : lhs.folders)f->remMsg(&lhs);for (auto f : rhs.folders)f->remMsg(&rhs);swap(lhs.folders, rhs.folders);swap(lhs.contents, rhs.contents);for (auto f : lhs.folders)f->addMsg(&lhs);for (auto f : rhs.folders)f->addMsg(&rhs);
}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);
}Message::Message(const Message& m) :contents(m.contents), folders(m.folders)
{add_to_Folders(m);
}void Message::remove_from_Folders()
{for (auto f : folders)f->remMsg(this);folders.clear();
}Message::~Message()
{remove_from_Folders();
}Message& Message::operator=(const Message& rhs)
{remove_from_Folders();contents = rhs.contents;folders = rhs.folders;add_to_Folders(rhs);return *this;
}void Message::print_debug()
{std::cout << contents << std::endl;
}void swap(Folder& lhs, Folder& rhs)
{using std::swap;for (auto m : lhs.msgs)m->remFlddr(&lhs);for (auto m : rhs.msgs)m->remFlddr(&rhs);swap(lhs.msgs, rhs.msgs);for (auto m : lhs.msgs)m->addFldr(&lhs);for (auto m : rhs.msgs)m->addFldr(&rhs);
}void Folder::add_to_Message(const Folder& f)
{for (auto m : f.msgs)m->addFldr(this);
}Folder::Folder(const Folder& f) :msgs(f.msgs)
{add_to_Message(f);
}void Folder::remove_to_Message()
{for (auto m : msgs)m->remFlddr(this);msgs.clear();
}Folder::~Folder()
{remove_to_Message();
}Folder& Folder::operator=(const Folder& rhs)
{remove_to_Message(); msgs = rhs.msgs;add_to_Message(rhs);return *this;
}void Folder::print_debug()
{for (auto m : msgs)std::cout << m->contents << " ";std::cout << std::endl;
}

练习13.38

我们并未使用拷贝交换方式来设计 Message 的赋值运算符。你认为其原因是什么?

对于动态分配内存的例子来说,拷贝交换方式是一种简洁的设计。而这里的 Message 类并不需要动态分配内存,用拷贝交换方式只会增加实现的复杂度。

练习13.39

编写你自己版本的 StrVec,包括自己版本的 reserve、capacity 和 resize。

头文件

#ifndef ex13_39_h
#define ex13_39_h#include <memory>
#include <string>class StrVec
{
public:StrVec() :elements(nullptr), first_free(nullptr), cap(nullptr) {}StrVec(const StrVec&);StrVec(std::initializer_list<std::string>);//ex13.40StrVec& operator=(const StrVec&);~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; }private:std::pair<std::string*, std::string*> 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*);//ex13.40private:std::string *elements;std::string *first_free;std::string *cap;std::allocator<std::string> alloc;
};#endif

CPP文件

#include "exercise13_39.h"void StrVec::push_back(const std::string& s)
{chk_n_alloc();alloc.construct(first_free++, s);
}std::pair<std::string*,std::string*>
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 (auto p = first_free; p != elements;)alloc.destroy(--p);alloc.deallocate(elements, cap - elements);}
}StrVec::StrVec(const StrVec& rhs)
{auto newdata = alloc_n_copy(rhs.begin(), rhs.end());elements = newdata.first;first_free = cap = newdata.second;
}
//ex13.40
StrVec::StrVec(std::initializer_list<std::string> 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);
}//ex13.40
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;
}

练习13.40

为你的 StrVec 类添加一个构造函数,它接受一个 initializer_list 参数。

头文件

#ifndef ex13_39_h
#define ex13_39_h#include <memory>
#include <string>class StrVec
{
public:StrVec() :elements(nullptr), first_free(nullptr), cap(nullptr) {}StrVec(const StrVec&);StrVec(std::initializer_list<std::string>);//ex13.40StrVec& operator=(const StrVec&);~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; }private:std::pair<std::string*, std::string*> 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*);//ex13.40private:std::string *elements;std::string *first_free;std::string *cap;std::allocator<std::string> alloc;
};#endif

CPP文件

#include "exercise13_39.h"void StrVec::push_back(const std::string& s)
{chk_n_alloc();alloc.construct(first_free++, s);
}std::pair<std::string*,std::string*>
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 (auto p = first_free; p != elements;)alloc.destroy(--p);alloc.deallocate(elements, cap - elements);}
}StrVec::StrVec(const StrVec& rhs)
{auto newdata = alloc_n_copy(rhs.begin(), rhs.end());elements = newdata.first;first_free = cap = newdata.second;
}
//ex13.40
StrVec::StrVec(std::initializer_list<std::string> 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);
}//ex13.40
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;
}