【 声明:版权所有,转载请标明出处,请勿用于商业用途。 联系信箱:libin493073668@sina.com】
13.1 拷贝、赋值与销毁
1.当定义一个类时,我们显式地或隐式地指定在此类型的对象拷贝、移动、赋值和销毁时做什么。一个类通过定义五种特殊的成员函数来控制这些操作,包括:拷贝构造函数,拷贝赋值运算符,移动构造函数,移动赋值运算符和析构函数。
2.在一个构造函数中,成员的初始化是在函数体执行之前完成的,且按照它们在类中出现的顺序进行初始化。在一个析构函数中,首先执行函数体,然后销毁成员。成员按照初始化顺序的逆序销毁。
3.我们可以通过将拷贝构造函数和拷贝赋值运算符定义为删除的函数来阻止拷贝。删除的函数是这样一种函数:我们虽然声明了它们,但不能以任何方式使用它们。在函数的参数列表后面加上=delete来指出我们希望将它定义为删除的。
13.2 拷贝控制和资源管理
1.当你编写赋值运算符时,有两点需要记住
⑴如果将一个对象赋予它自身,赋值运算符必须能正确工作
⑵大多数赋值运算符组合了析构函数和拷贝构造函数的工作
13.3 交换操作
1.除了定义拷贝控制成员,管理资源的类通常还定义一个名为swap的函数。对于那些与重排元素顺序的算法一起使用的类,定义swap是非常重要的。这类算法在需要交换两个元素时会调用swap。
13.6 对象移动
1.虽然不能将一个右值引用直接绑定到一个左值上,但我们可以显式地将一个左值转换为对应的右值引用类型。我们还可以通过调用名为move的新标准库函数来获得绑定到左值上的右值引用,此函数定义在头文件utility中。
与大多数标准库名字的使用不同,对move我们不提供using声明。我们直接调用std::move而不是move。
2.只有当一个类没有定义任何自己版本的拷贝控制成员,且它的所有数据成员都能移动构造或移动赋值时,编译器才会为它合成移动构造函数或移动赋值运算符。
PS:部分练习答案
练习13.3
当我们拷贝一个StrBlob的时候,shared_ptr的use_count会增加1
当我们拷贝一个StrBlobPtr的时候,weak_ptr的use_count不会变化
练习13.5
#ifndef CP5_ex13_05_h
#ifndef CP5_ex13_05_h
#include <string>
class HasPtr
{
public:
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){}
private:
std::string* ps;
int i;
};
#endif
练习13.6
#ifndef CP5_ex13_08_h
#ifndef CP5_ex13_08_h
#include <string>
class HasPtr
{
public:
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=(const HasPtr& hp)
{
std::string *new_ps = new std::string(*hp.ps);
delete ps;
ps = new_ps;
i = hp.i;
return *this;
}
private:
std::string* ps;
int i;
};
#endif
练习13.11
#ifndef CP5_ex13_08_h
#ifndef CP5_ex13_08_h
#include <string>
class HasPtr
{
public:
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=(const HasPtr& hp)
{
std::string *new_ps = new std::string(*hp.ps);
delete ps;
ps = new_ps;
i = hp.i;
return *this;
}
~HasPtr(){delete ps;}
private:
std::string* ps;
int i;
};
#endif
练习13.13
#include <iostream>
#include <vector>
#include <initializer_list>
struct X
{
X()
{
std::cout << "X()" << std::endl;
}
X(const X&)
{
std::cout << "X(const X&)" << std::endl;
}
X& operator=(const X&)
{
std::cout << "X& operator=(const X&)" << std::endl;
return *this;
}
~X()
{
std::cout << "~X()" << std::endl;
}
};
void f(const X& rx, X x)
{
std::vector<X> vec;
vec.reserve(2);
vec.push_back(rx);
vec.push_back(x);
}
int main()
{
X* px = new X;
f(*px, *px);
delete px;
return 0;
}
练习13.17
13.14
#include <iostream>
class numbered
{
public:
numbered()
{
static int unique = 10;
mysn = unique++;
}
int mysn;
};
void f(numbered s)
{
std::cout << s.mysn << std::endl;
}
int main()
{
numbered a, b = a, c = b;
f(a);
f(b);
f(c);
}
13.15
#include <iostream>
class numbered
{
public:
numbered()
{
static int unique = 10;
mysn = unique++;
}
numbered(const numbered& n)
{
mysn = n.mysn + 1;
}
int mysn;
};
void f(numbered s)
{
std::cout << s.mysn << std::endl;
}
int main()
{
numbered a, b = a, c = b;
f(a);
f(b);
f(c);
}
13.16
#include <iostream>
class numbered
{
public:
numbered()
{
static int unique = 10;
mysn = unique++;
}
numbered(const numbered& n)
{
mysn = n.mysn + 1;
}
int mysn;
};
void f(const numbered& s)
{
std::cout << s.mysn << std::endl;
}
int main()
{
numbered a, b = a, c = b;
f(a);
f(b);
f(c);
}
练习13.18
ex13_18.h
#ifndef CP5_ex13_18_h
#define CP5_ex13_18_h
#include <string>
using std::string;
class Employee
{
public:
Employee();
Employee(const string& name);
const int id() const {return id_;}
private:
string name_;
int id_;
static int s_increment;
};
#endif
ex13_18.cpp
#include "ex13_18.h"
int Emoloyee::s_increment = 0;
Employee::Employee()
{
id_ = s_increment++;
}
Employee::Employee(const string& name)
{
id_ = s_increment++;
name_ = name;
}
练习13.19
不需要,因为这没有实际意义,在现实生活中员工是不能拷贝的
#ifndef CP5_ex13_19_h
#define CP5_ex13_19_h
#include <string>
using std::string;
class Employee
{
public:
Employee();
Employee(const string& name);
Employee(const Employee&) = delete;
Employee& operator=(const Employee&) = delete;
const int id() const {return id_;}
private:
string name_;
int id_;
static int s_increment;
};
#endif
练习13.26
ex13_26.h
#ifndef CP5_ex13_26_h
#define CP5_ex13_26_h
#include <vector>
#include <string>
#include <initializer_list>
#include <memory>
#include <exception>
using std::vector;
using std::string;
class ConstStrBlobPtr;
class StrBlob
{
public:
using size_type = vector<string>::size_type;
friend class ConstStrBlobPtr;
ConstStrBlobPtr begin() const;
ConstStrBlobPtr end() const;
StrBlob() : data(std::make_shared<vector<string>>()) {}
StrBlob(std::initializer_list<string> il)
: data(std::make_shared<vector<string>>(il))
{
}
StrBlob(const StrBlob& sb)
: data(std::make_shared<vector<string>>(*sb.data))
{
}
StrBlob& operator=(const StrBlob& sb);
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()
{
check(0, "pop_back on empty StrBlob");
data->pop_back();
}
std::string& front()
{
check(0, "front on empty StrBlob");
return data->front();
}
std::string& back()
{
check(0, "back on empty StrBlob");
return data->back();
}
const std::string& front() const
{
check(0, "front on empty StrBlob");
return data->front();
}
const std::string& back() const
{
check(0, "back on empty StrBlob");
return data->back();
}
private:
void check(size_type i, const string& msg) const
{
if (i >= data->size()) throw std::out_of_range(msg);
}
private:
std::shared_ptr<vector<string>> data;
};
class ConstStrBlobPtr
{
public:
ConstStrBlobPtr() : curr(0) {}
ConstStrBlobPtr(const StrBlob& a, size_t sz = 0) : wptr(a.data), curr(sz) {} // should add const
bool operator!=(ConstStrBlobPtr& p)
{
return p.curr != curr;
}
const string& deref() const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
ConstStrBlobPtr& incr()
{
check(curr, "increment past end of StrBlobPtr");
++curr;
return *this;
}
private:
std::shared_ptr<vector<string>> check(size_t i, const string& msg) const
{
auto ret = wptr.lock();
if (!ret) throw std::runtime_error("unbound StrBlobPtr");
if (i >= ret->size()) throw std::out_of_range(msg);
return ret;
}
std::weak_ptr<vector<string>> wptr;
size_t curr;
};
#endif
ex13_26.cpp
#include "ex13_26.h"
ConstStrBlobPtr StrBlob::begin() const
{
return ConstStrBlobPtr(*this);
}
ConstStrBlobPtr StrBlob::end() const
{
return ConstStrBlobPtr(*this, data->size());
}
StrBlob& StrBlob::operator=(const StrBlob& sb)
{
data = std::make_shared<vector<string>>(*sb.data);
return *this;
}
练习13.27
#ifndef CP_ex13_27_h
#define CP_ex13_27_h
#include <string>
class HasPtr
{
public:
HasPtr(const std::string& s = std::string()):ps(new std::string(s)),i(0),use(new size_t(1)) {}
HasPtr(const HasPtr& hp):ps(hp.ps),i(hp.i),use(hp.use)
{
++*use;
}
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()
{
if(--*use == 0)
{
delete ps;
delete use;
}
}
private:
std::string *ps;
int i;
size_t *use;
};
#endif
练习13.28
ex13_28.h
#ifndef CP5_ex13_28_h
#define CP5_ex13_28_h
#include <string>
using std::string;
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;
};
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;
};
#endif
ex13_28.cpp
#include "ex13_28.h"
TreeNode& TreeNode::operator=(const TreeNode& rhs)
{
++*rhs.count;
if (--*count == 0)
{
if (left)
{
delete left;
left = nullptr;
}
if (right)
{
delete right;
right = nullptr;
}
delete count;
count = nullptr;
}
value = rhs.value;
left = rhs.left;
right = rhs.right;
count = rhs.count;
return *this;
}
BinStrTree& BinStrTree::operator=(const BinStrTree& bst)
{
TreeNode* new_root = new TreeNode(*bst.root);
delete root;
root = new_root;
return *this;
}
练习13.30
#ifndef CP5_ex13_30_h
#define CP5_ex13_30_h
#include <string>
#include <iostream>
class HasPtr
{
public:
friend void swap(HasPtr&, HasPtr&);
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=(const HasPtr& hp)
{
auto new_p = new std::string(*hp.ps);
delete ps;
ps = new_p;
i = hp.i;
return *this;
}
~HasPtr()
{
delete ps;
}
void show()
{
std::cout << *ps << std::endl;
}
private:
std::string* ps;
int i;
};
void swap(HasPtr& lhs, HasPtr& rhs)
{
using std::swap;
swap(lhs.ps, rhs.ps);
swap(lhs.i, rhs.i);
std::cout << "call swap(HasPtr& lhs, HasPtr& rhs)" << std::endl;
}
#endif
练习13.31
#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()
{
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.34 & 13.36 & 13.37
ex13_34_36_37.h
#ifndef CP5_ex13_34_36_37_h
#define CP5_ex13_34_36_37_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& str = "") : contents(str) {}
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 remFldr(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_36_37.cpp
#include "ex13_34_36_37.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);
}
// Message
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);
}
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;
}
// Folder
void swap(Folder& lhs, Folder& rhs)
{
using std::swap;
for (auto m : lhs.msgs) m->remFldr(&lhs);
for (auto m : rhs.msgs) m->remFldr(&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->remFldr(this);
}
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.39
ex13_39.h
#ifndef CP5_ex13_39_h
#define CP5_ex13_39_h
#include <memory>
#include <string>
class StrVec
{
public:
StrVec() : elements(nullptr), first_free(nullptr), cap(nullptr) {}
StrVec(const StrVec&);
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;
}
void reserve(size_t new_cap);
void resize(size_t count);
void resize(size_t count, const std::string&);
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);
private:
std::string* elements;
std::string* first_free;
std::string* cap;
std::allocator<std::string> alloc;
};
#endif
ex13_39.cpp
#include "ex13_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;
}
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);
}
}
练习13.40
ex13_40.h
#ifndef CP5_ex13_40_h
#define CP5_ex13_40_h
#include <memory>
#include <string>
#include <initializer_list>
class StrVec
{
public:
StrVec() : elements(nullptr), first_free(nullptr), cap(nullptr) {}
StrVec(const StrVec&);
StrVec(std::initializer_list<std::string>);
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;
}
void reserve(size_t new_cap);
void resize(size_t count);
void resize(size_t count, const std::string&);
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*);
private:
std::string* elements;
std::string* first_free;
std::string* cap;
std::allocator<std::string> alloc;
};
#endif
ex13_40.cpp
#include "ex13_40.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);
}
}
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<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);
}
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);
}
}
练习13.42
ex13_42_StrVec.h
#ifndef CP5_STRVEC_H
#define CP5_STRVEC_H
#include <memory>
#include <string>
#include <initializer_list>
class StrVec
{
public:
StrVec() : elements(nullptr), first_free(nullptr), cap(nullptr) {}
StrVec(const StrVec&);
StrVec(std::initializer_list<std::string>);
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;
}
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<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*);
private:
std::string* elements;
std::string* first_free;
std::string* cap;
std::allocator<std::string> alloc;
};
#endif
ex13_42_StrVec.h
#include "ex13_42_StrVec.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);
}
}
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<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);
}
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);
}
}
ex13_42_TextQuery.h
#ifndef CP5_TEXTQUERY_H
#define CP5_TEXTQUERY_H
#include <string>
#include <memory>
#include <iostream>
#include <fstream>
#include <map>
#include <set>
#include "ex13_42_StrVec.h"
class QueryResult;
class TextQuery
{
public:
TextQuery(std::ifstream&);
QueryResult query(const std::string&) const;
private:
std::shared_ptr<StrVec> input;
std::map<std::string, std::shared_ptr<std::set<size_t>>> result;
};
class QueryResult
{
public:
friend std::ostream& print(std::ostream&, const QueryResult&);
public:
QueryResult(const std::string& s, std::shared_ptr<std::set<size_t>> set,
std::shared_ptr<StrVec> v)
: word(s), nos(set), input(v)
{
}
private:
std::string word;
std::shared_ptr<std::set<size_t>> nos;
std::shared_ptr<StrVec> input;
};
std::ostream& print(std::ostream&, const QueryResult&);
#endif
ex13_42_TextQuery.cpp
#include "ex13_42_TextQuery.h"
#include <sstream>
#include <algorithm>
using std::string;
TextQuery::TextQuery(std::ifstream& ifs) : input(new StrVec)
{
size_t lineNo = 0;
for (string line; std::getline(ifs, line); ++lineNo)
{
input->push_back(line);
std::istringstream line_stream(line);
for (string text, word; line_stream >> text; word.clear())
{
std::remove_copy_if(text.begin(), text.end(), std::back_inserter(word), ispunct);
auto& nos = result[word];
if (!nos) nos.reset(new std::set<size_t>);
nos->insert(lineNo);
}
}
}
QueryResult TextQuery::query(const string& str) const
{
static std::shared_ptr<std::set<size_t>> nodate(new std::set<size_t>);
auto found = result.find(str);
if (found == result.end())
return QueryResult(str, nodate, input);
else
return QueryResult(str, found->second, input);
}
std::ostream& print(std::ostream& out, const QueryResult& qr)
{
out << qr.word << " occurs " << qr.nos->size()
<< (qr.nos->size() > 1 ? " times" : " time") << std::endl;
for (auto i : *qr.nos)
out << "\t(line " << i + 1 << ") " << qr.input->at(i) << std::endl;
return out;
}
ex13_42.cpp
#include "ex13_42_TextQuery.h"
#include <iostream>
void runQueries(std::ifstream& infile)
{
TextQuery tq(infile);
while (true)
{
std::cout << "enter word to look for, or q to quit: ";
std::string s;
if (!(std::cin >> s) || s == "q") break;
print(std::cout, tq.query(s)) << std::endl;
}
}
int main()
{
std::ifstream file("storyDataFile.txt");
runQueries(file);
}
练习13.43
for_each(elements, first_free, [this](std::string &rhs){ alloc.destroy(&rhs); });
练习13.44 & 13.47 & 13.48
ex13_44_47.h
#ifndef CP5_STRING_H
#define CP5_STRING_H
#include <memory>
class String
{
public:
String() : String("") {}
String(const char*);
String(const String&);
String& operator=(const String&);
~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<char*, char*> alloc_n_copy(const char*, const char*);
void range_initializer(const char*, const char*);
void free();
private:
char* elements;
char* end;
std::allocator<char> alloc;
};
#endif
ex13_44_47.cpp
#include "ex13_44_47.h"
#include <algorithm>
#include <iostream>
std::pair<char*, char*> 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<char*>(s);
while (*sl) ++sl;
range_initializer(s, ++sl);
}
String::String(const String& rhs)
{
range_initializer(rhs.elements, rhs.end);
std::cout << "copy constructor" << std::endl;
}
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;
std::cout << "copy-assignment" << std::endl;
return *this;
}
ex13_48.cpp
#include "ex13_44_47.h"
#include <vector>
#include <iostream>
void foo(String x)
{
std::cout << x.c_str() << std::endl;
}
void bar(const String& x)
{
std::cout << x.c_str() << std::endl;
}
String baz()
{
String ret("world");
return ret;
}
int main()
{
char text[] = "world";
String s0;
String s1("hello");
String s2(s0);
String s3 = s1;
String s4(text);
s2 = s1;
foo(s1);
bar(s1);
foo("temporary");
bar("temporary");
String s5 = baz();
std::vector<String> svec;
svec.reserve(8);
svec.push_back(s0);
svec.push_back(s1);
svec.push_back(s2);
svec.push_back(s3);
svec.push_back(s4);
svec.push_back(s5);
svec.push_back(baz());
svec.push_back("good job");
for (const auto& s : svec)
{
std::cout << s.c_str() << std::endl;
}
}
练习13.49
ex13_49_StrVec.h
#ifndef CP5_STRVEC_H_
#define CP5_STRVEC_H_
#include <memory>
#include <string>
#include <initializer_list>
#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<std::string>);
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<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*);
private:
std::string* elements;
std::string* first_free;
std::string* cap;
std::allocator<std::string> alloc;
};
#endif
ex13_49_StrVec.cpp
#include "ex13_49_StrVec.h"
#include <algorithm> // for_each
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_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<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);
}
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)
{
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;
}
ex13_49_String.h
#ifndef CP5_STRING_H__
#define CP5_STRING_H__
#include <memory>
#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<char*, char*> alloc_n_copy(const char*, const char*);
void range_initializer(const char*, const char*);
void free();
private:
char* elements;
char* end;
std::allocator<char> alloc;
};
#endif
ex13_49_String.cpp
#include "ex13_49_String.h"
#include <algorithm>
std::pair<char*, char*> 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<char*>(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;
}
ex13_49_Message.h
#ifndef CP5_MESSAGE_H_
#define CP5_MESSAGE_H_
#include <string>
#include <set>
#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<Folder*> 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<Message*> 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
ex13_49_Message.cpp
#include "ex13_49_Message.h"
#include <iostream>
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;
}
练习13.53
ex13_53.h
#ifndef CP5_ex13_53_h
#define CP5_ex13_53_h
#include <string>
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();
private:
std::string* ps;
int i;
};
#endif
ex13_53.cpp
#include "ex13_53.h"
#include <iostream>
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()
{
std::cout << "call destructor" << std::endl;
delete ps;
}
练习13.55
void push_back(string &&s) { data->push_back(std::move(s)); }
练习13.58
#include <vector>
#include <iostream>
#include <algorithm>
using std::vector;
using std::sort;
class Foo
{
public:
Foo sorted()&&;
Foo sorted() const&;
private:
vector<int> data;
};
Foo Foo::sorted() &&
{
sort(data.begin(), data.end());
std::cout << "&&" << std::endl; // debug
return *this;
}
Foo Foo::sorted() const &
{
std::cout << "const &" << std::endl; // debug
return Foo(*this).sorted(); // Exercise 13.57
}
int main()
{
Foo().sorted(); // call "&&"
Foo f;
f.sorted(); // call "const &"
}