13.2节练习

练习13.22 假定我们希望HasPtr的行为像一个值。即,对于对象所指向的string成员,每个对象都有一份自己的拷贝。我们将在下一节介绍拷贝控制成员的定义。但是,你已经学习了定义这些成员所需的所有知识。在继续学习下一节之前,为HasPtr编写拷贝构造函数和拷贝赋值运算符。

class HasPtr {
public:
	HasPtr() = default;
	HasPtr(const std::string &s) :ps(new std::string(s)), i(0) {}
	HasPtr(const HasPtr& m) :ps(new std::string(*m.ps)), i(m.i) {}
	HasPtr& operator=(const HasPtr& rhs)
	{
		ps = new std::string(*rhs.ps);
		i = (rhs.i);
		return *this;
	}
private:
	std::string *ps;
	int i;
};

练习13.23 比较上一节练习中你编写的拷贝控制成员和这一节中的代码。确定你理解了你的代码和我们的代码之间的差异(如果有的话)。

拷贝赋值运算符要考虑到自赋值的情况。

#include <iostream>
#include <string>
using namespace std;
class HasPtr {
public:
	HasPtr(const std::string &s = std::string()) :ps(new std::string(s)), i(0) {}
	HasPtr(const HasPtr &m) :ps(new std::string(*m.ps)), i(m.i) {}
	HasPtr& operator=(const HasPtr &rhs)
	{
		auto newp = new std::string(*rhs.ps);     //new动态分配
		delete ps;
		ps = newp;
		i = rhs.i;
		return *this;
	}
	~HasPtr() { delete ps; }
private:
	std::string *ps;
	int i;
};

练习13.24 如果本节中的HasPtr版本未定义析构函数,将会发生什么?如果未定义拷贝构造函数,将会发生什么?

如果未定义析构函数,会合成析构函数,将不会删除ps分配的动态内存,造成内存泄漏。

如果为定义拷贝构造函数,会合成拷贝构造函数。当两个对象的指针简单拷贝,会造成多个HasPtr可能指向同一个内存,我们对相同内存使用两次delete结果将是未定义的。


练习13.25假定希望定义StbBlob类值版本,而且希望继续使用shared_ptr,这样我们的StrBlobPtr类就仍能指向vector的weak_ptr了。你修改后的类将需要一个拷贝构造函数和一个拷贝赋值运算符,但不需要析构函数。解释拷贝构造函数需要做什么。解释为什么不需要析构函数。

拷贝构造函数只需简单的拷贝数据成员,因为成员data是智能指针,无需担心像HasPtr那样造成内存泄漏。

智能指针根据实际情况自动释放内存。

练习13.26 对上一题中描述的StrBlob类,编写你自己的版本。

class StrBlob
{
public:
	typedef	std::vector<std::string>::size_type size_type;
	StrBlob() :data(std::make_shared<std::vector<std::string>>()) {}
	StrBlob(std::initializer_list<std::string> il) :data(std::make_shared<std::vector<std::string>>(il)) {}

	size_type size() const { return data->size(); }
	bool empty() const { return data->empty(); }
	void push_back(const std::string &t) { data->push_back(t); }
	void pop_back();
	std::string& front() { front_check(); return data->front(); }
	std::string& back() { back_check(); return data->back(); }
	const std::string& front() const { front_check(); return data->front(); }
	const std::string& back()const { back_check(); return data->back(); }
	//拷贝构造函数
	StrBlob(const StrBlob &m) :data(m.data) {}
	//赋值运算符
	StrBlob& operator=(const StrBlob &rhs) { data = rhs.data; return *this; }
private:
	std::shared_ptr<std::vector<std::string>> data;
	void check(size_t, const std::string &) const;
	void front_check() const;
	void back_check() const;
};

void StrBlob::check(size_t i, const std::string& msg) const
{
	if (i >= data->size()) {
		throw std::out_of_range(msg);
	}
}
void StrBlob::pop_back()
{
	check(0, "pop_back on empty StrBlob");
	data->pop_back();
}
void StrBlob::front_check() const
{
	check(0, "front_back on empty StrBlob");
}
void StrBlob::back_check() const 
{
	check(0, "back_chcek on empty StrBlob");
}


练习13.27定义你自己使用的引用计数版本的HasPtr。

#include <string>
#include <memory>
class HasPtr {
public:
	HasPtr(const std::string &s = std::string()) :ps(new std::string(s)), i(0), use(new std::size_t(1)) {};
	HasPtr(const HasPtr&m) :ps(m.ps), i(m.i), use(m.use) { ++*use; }
	HasPtr& operator=(const HasPtr&);
	~HasPtr();
private:
	std::string *ps;
	int i;
	std::size_t *use;
};
HasPtr& HasPtr::operator=(const HasPtr& rhs)
{
	++*rhs.use;
	if (--*use == 0) {
		delete ps;
		delete use;
	}
	ps = rhs.ps;
	i = rhs.i;
	use = rhs.use;
	return *this;
}
HasPtr::~HasPtr()
{
	if (--*use == 0) {
		delete ps;
		delete use;
	}
}

练习13.28 给定下面的类,为其实现一个默认构造函数和必要的拷贝控制成员。

(a)
class TreeNode {
private:
	std::string value;
	int count;
	TreeNode *left;
	TreeNode *right;
};
(b)
class BinStrTree{
private:
	TreeNode *root;
};
//a
class TreeNode {
public:
	TreeNode(const std::string &s, int i) :value(s), count(1), left(nullptr), right(nullptr) {}
	TreeNode(const TreeNode &m) :value(m.value), count(m.count), left(m.left), right(m.right) {}
	TreeNode& operator=(const TreeNode &rhs)
	{
		if (value == rhs.value) {
			++count;
		}
		return *this;
	}
private:
	std::string value;
	int count;
	TreeNode *left;
	TreeNode *right;
};
//b
class BinStrTree{
public:
	BinStrTree():root(nullptr){}
	BinStrTree(const BinStrTree &m) :root(m.root) {}
private:
	TreeNode *root;
};


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值