习题13-21
不需要,因为都是用的智能指针,不需要析构函数,合成的拷贝控制成员已经满足要求,拷贝控制成员没有必要;
习题13-22
HasPtr(const HasPtr &p) : ps(new string(*p.ps)), i(p.i) {}
HasPtr& operator=(const HasPtr &p)
{
auto newp = new string(*p.ps);
delete ps;
ps = newp;
i = p.i;
return *this;
}
HasPtr& operator=(const string str)
{
*ps=str;
return *this;
}
习题13-23
没有差异
习题13-24
如果未定义析构函数,默认合成的析构函数会导致动态内存无法释放;
如果未定义拷贝构造函数,会默认将数据成员依次赋值拷贝,导致指针互相拷贝,从而指向同一内存;
习题13-25
拷贝构造函数和拷贝赋值运算符必须重新分配动态内存;不需要析构函数,因为智能指针的动态内存是自动分配的;
习题13-26
#pragma once
#include<vector>
#include<string>
#include<initializer_list>
#include<memory>
#include<stdexcept>
using namespace std;
class StrBlobPtr;
class StrBlob {
friend class StrBlobPtr;
public:
typedef vector<string>::size_type size_type;
StrBlob();
StrBlob(initializer_list<string> il);
StrBlob(vector<string> *p);
StrBlob(StrBlob &s);
StrBlob &operator=(StrBlob &rhs);
size_type size() const { return data->size(); };
bool empty() const { return data->empty(); }
void push_back(const string &t) { data->push_back(t); }
void pop_back();
string &front();
const string &front() const;
string &back();
const string &back()const;
StrBlobPtr begin();
StrBlobPtr end();
StrBlobPtr begin() const;
StrBlobPtr end()const;
private:
shared_ptr<vector<string>> data;
void check(size_type i, const string &msg) const;
};
inline StrBlob::StrBlob() :data(make_shared<vector<string>>()) { }
inline StrBlob::StrBlob(initializer_list<string> il):
data(make_shared<vector<string>>(il)){}
inline StrBlob::StrBlob(vector<string> *p):data(p){}
inline StrBlob::StrBlob(StrBlob &s):data(make_shared<vector<string>>(*s.data)){}
inline StrBlob &StrBlob::operator=(StrBlob &rhs)
{
data = make_shared<vector<string>>(*rhs.data);
return *this;
}
inline void StrBlob::check(size_type i, const string &msg)const
{
if (i >= data->size())
throw out_of_range(msg);
}
inline string &StrBlob::front()
{
check(0, "front on empty StrBlob");
return data->front();
}
inline const string &StrBlob::front() const
{
check(0, "front on empty StrBlob");
return data->front();
}
inline string&StrBlob::back()
{
check(0, "back on empty StrBlob");
return data->back();
}
inline const string&StrBlob::back()const
{
check(0, "back on empty StrBlob");
return data->back();
}
inline void StrBlob::pop_back()
{
check(0, "pop_back on empty StrBlob");
data->pop_back();
}
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){}
StrBlobPtr(const StrBlob &a,size_t sz=0):wptr(a.data),curr(sz){}
string &deref()const;
string &deref(int off)const;
StrBlobPtr &incr();
private:
shared_ptr<vector<string>> check(size_t, const string &)const;
weak_ptr<vector<string>> wptr;
size_t curr;
};
inline shared_ptr<vector<string>> StrBlobPtr::check(size_t i, const string &msg)const
{
auto ret = wptr.lock();
if (!ret)
throw runtime_error("unbound StrBlobPtr");
if (i > ret->size())
throw out_of_range(msg);
return ret;
}
inline string &StrBlobPtr::deref()const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
inline string &StrBlobPtr::deref(int off)const
{
auto p = check(curr + off, "dereference past end");
return (*p)[curr + off];
}
inline StrBlobPtr &StrBlobPtr::incr()
{
check(curr, "increment past end of StrBlobPtr");
++curr;
return *this;
}
inline StrBlobPtr StrBlob::begin()
{
return StrBlobPtr(*this);
}
inline StrBlobPtr StrBlob::end()
{
auto ret = StrBlobPtr(*this, data->size());
return ret;
}
inline StrBlobPtr StrBlob::begin()const
{
return StrBlobPtr(*this);
}
inline StrBlobPtr StrBlob::end()const
{
auto ret = StrBlobPtr(*this, data->size());
return ret;
}
inline bool eq(const StrBlobPtr &lhs, const StrBlobPtr &rhs)
{
auto l = lhs.wptr.lock(), r = rhs.wptr.lock();
if (l == r)
return (!r || lhs.curr == rhs.curr);
else
return false;
}
inline bool neq(const StrBlobPtr &lhs, const StrBlobPtr &rhs)
{
return !eq(lhs, rhs);
}
习题3-27
class HasPtr
{
HasPtr(const string &s=string()):ps(new string(s)),i(0),use(new size_t(1)){}
HasPtr(const HasPtr &p):ps(p.ps),i(p.i),use(p.use){++*use}
HasPtr &operator=(const HasPtr&);
HasPtr &operator=(const string &);
string &operator *();
~HasPtr();
private:
string *ps;
int i;
size_t *use;
};
HasPtr::~HasPtr()
{
if (--*use == 0)
{
delete ps;
delete 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::operator=(const string &rhs)
{
*ps = rhs;
return *this;
}
string &HasPtr::operator*()
{
return *ps;
}
习题13-28
书上的count没有解引用符号,二叉树不太会,答案中把count前面加了一个解引用符号,做法与习题13-27类似
class TreeNode
{
public:
TreeNode() : value(string()), count(new int(1)), left(nullptr), right(nullptr) {}
TreeNode(const TreeNode &rhs) : value(rhs.value), count(rhs.count), left(rhs.left), right(rhs.right) { ++*count; }
TreeNode& operator=(const TreeNode &rhs);
~TreeNode()
{
if (--*count == 0)
{
if (left)
{
delete left;
left = nullptr;
}
if (right)
{
delete right;
right = nullptr;
}
delete count;
count = nullptr;
}
}
private:
std::string value;
int *count;
TreeNode *left;
TreeNode *right;
};
TreeNode& TreeNode::operator=(const TreeNode &rhs)
{
++*rhs.count;
if (--*count == 0)
{
if (left)
{
delete left;
}
if (right)
{
delete right;
}
delete count;
}
value = rhs.value;
left = rhs.left;
right = rhs.right;
count = rhs.count;
return *this;
}
class BinStrTree
{
public:
BinStrTree() : root(new TreeNode()) {}
BinStrTree(const BinStrTree &bst) : root(new TreeNode(*bst.root)) {}
BinStrTree& operator=(const BinStrTree &bst);
~BinStrTree() { delete root; }
private:
TreeNode *root;
};
BinStrTree& BinStrTree::operator=(const BinStrTree &bst)
{
TreeNode *new_root = new TreeNode(*bst.root);
delete root;
root = new_root;
return *this;
}
#endif
习题13-29
这里调用的参数是ps和i,分别为指针和整型,匹配到的swap函数是std::swap而不是swap(HasPtr &,HasPtr &),所以不会导致递归;
习题13-30
inline swap(HasPtr&lhs, HasPtr&rhs)
{
cout << "swap HasPtr" << endl;
swap(lhs.ps, rhs.ps);
swap(lhs.i, rhs.i);
}