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

文章目录

      • 练习13.31
      • 练习13.32
      • 练习13.23
      • 练习13.34
        • 头文件
        • CPP文件
      • 练习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 
#include 

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 
#include 

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 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 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 

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 
#include 

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 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 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 

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 
#include 

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 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 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 

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 
#include 

class StrVec
{
public:
	StrVec() :elements(nullptr), first_free(nullptr), cap(nullptr) {}
	StrVec(const StrVec&);
	StrVec(std::initializer_list);//ex13.40
	StrVec& 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 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.40

private:
	std::string *elements;
	std::string *first_free;
	std::string *cap;
	std::allocator 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
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 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 
#include 

class StrVec
{
public:
	StrVec() :elements(nullptr), first_free(nullptr), cap(nullptr) {}
	StrVec(const StrVec&);
	StrVec(std::initializer_list);//ex13.40
	StrVec& 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 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.40

private:
	std::string *elements;
	std::string *first_free;
	std::string *cap;
	std::allocator 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
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 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;
}

你可能感兴趣的:(C++《i+1》,c++,开发语言)