13.26
class HasPtr {
public:
HasPtr() = default;
HasPtr(const string& s = string()) :
ps(new string(s)), i(0) {}
HasPtr(const HasPtr& p) :
ps(new string(*p.ps)), i(p.i) {}
HasPtr& operator=(const HasPtr& rhs){
auto newp = new string(*rhs.ps);
delete ps;
ps = newp;
i = rhs.i;
return *this;
}
~HasPtr() { delete ps; }
private:
string* ps;
int i;
};
13.27
class HasPtr {
public:
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& 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:
string* ps;
int i;
size_t* use; //引用计数
};
13.28
#include<iostream>
#include<vector>
#include<string>
using namespace std;
class TreeNode {
public:
TreeNode() :
value(), count(0), left(nullptr), right(nullptr) {}
TreeNode(const string& s, int c, TreeNode& l, TreeNode& r) :
value(s), count(c), left(new TreeNode(l)), right(new TreeNode(r)) {}
TreeNode(const TreeNode& t) :
value(t.value), count(t.count) {
if (t.left != nullptr)
left = new TreeNode(*t.left);
else
left = nullptr;
if (t.right != nullptr)
right = new TreeNode(*t.right);
else
right = nullptr;
}
TreeNode& operator=(const TreeNode& t) {
value = t.value;
count = t.count;
if (t.left != nullptr)
left = new TreeNode(*t.left);
else
left = nullptr;
if (t.right != nullptr)
right = new TreeNode(*t.right);
else
right = nullptr;
return *this;
}
~TreeNode() {
if (left != nullptr)
delete left;
if (right != nullptr)
delete right;
}
private:
string value;
int count;
TreeNode* left;
TreeNode* right;
};
class BinStrTree {
public:
BinStrTree() :
root(new TreeNode()) {}
BinStrTree(const TreeNode& t) :
root(new TreeNode(t)) {}
BinStrTree(const BinStrTree& bt) :
root(new TreeNode(*bt.root)) {}
BinStrTree& operator=(const BinStrTree& bt) {
auto newt = new BinStrTree(bt);
delete root;
root = newt->root;
return *this;
}
~BinStrTree() { delete root; }
private:
TreeNode* root;
};
int main()
{
TreeNode n1, n2, n4, n5;
TreeNode n6("hello", 3, n4, n5);
n2 = n6;
TreeNode n3(n6);
BinStrTree b1;
BinStrTree b2(n6);
b1 = b2;
BinStrTree b3(b1);
system("pause");
return 0;
}
13.27
#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
static int n = 0;
class HasPtr {
friend void swap(HasPtr&, HasPtr&);
friend bool operator<(HasPtr& lhs, HasPtr& rhs);
public:
HasPtr(const string& s = string()) :
ps(new string(s)), i(0) {}
HasPtr(const HasPtr& p) :
ps(new string(*p.ps)), i(p.i) {}
HasPtr& operator=(HasPtr rhs) {
swap(*this, rhs);
return *this;
}
void print() { cout << *ps << endl; }
~HasPtr() { delete ps; }
private:
string* ps;
int i;
};
inline
void swap(HasPtr& lhs, HasPtr& rhs) {
using std::swap;
swap(lhs.ps, rhs.ps);
swap(lhs.i, rhs.i);
n++;
cout << "swap" << endl;
}
bool operator<(HasPtr& lhs, HasPtr& rhs) {
return *lhs.ps < *rhs.ps;
}
int main()
{
vector<HasPtr> vec{ (string)"sfdd" };
for (int i = 0; i < 1000; ++i)
vec.push_back(string("dzx"));
std::sort(vec.begin(), vec.end());
cout << n << endl;
//for (auto m : vec)
// m.print();
return 0;
}
元素数目过少时sort使用插入排序,未使用swap,在VS中临界值似乎为32。
当元素数目变大时,sort会使用快速排序,此时使用自定义版本的swap,当剩余无序元素小于临界值后继续使用插入排序。
注意添加元素时不能让所有元素全部相等,不然编译器就不会使用快速排序,也就不会调用swap。(坑了我好久…)
13.37
h
#ifndef TEST_H
#define TEST_H
#include <set>
using namespace std;
class Folder;
class Message {
friend class Folder;
friend void swap(Message&, Message&);
public:
explicit Message(const string& str = "") :
contents(str) {}
Message(const Message&);
Message& operator=(const Message&);
~Message();
void save(Folder&);
void remove(Folder&);
void addfol(Folder*);
void remfol(Folder*);
void print();
void test();
private:
string contents;
set<Folder*> folders;
void add_to_Folders(const Message&);
void remove_from_Folders();
};
class Folder {
friend class Message;
friend void swap(Message&, Message&);
public:
Folder() = default;
Folder(const Folder& f);
Folder& operator=(const Folder&);
~Folder();
void addMsg(Message*);
void remMsg(Message*);
void print();
private:
set<Message*> messages;
void add_to_Messages(const Folder&);
void remove_from_Messages();
};
#endif
cpp
#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
#include"test.h"
using namespace std;
//函数定义
void swap(Message& lhs, Message& rhs)
{
using std::swap;
//移除保存双方的Folder的记录
for (auto f : lhs.folders)
f->remMsg(&lhs);
for (auto f : lhs.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 Folder::print()
{
cout << "Messages:";
for (auto m : messages)
{
cout << " " << m->contents;
}
cout << endl;
}
void Message::print()
{
cout << "Save in " << folders.size() << " Folders" << endl;
}
void Message::test()
{
Folder f1;
folders.insert(&f1);
}
//Message定义
Message::Message(const Message& m) :
contents(m.contents), folders(m.folders)
{
add_to_Folders(m);
}
Message& Message::operator=(const Message& rhs)
{
remove_from_Folders();
contents = rhs.contents;
folders = rhs.folders;
add_to_Folders(rhs);
return *this;
}
Message::~Message()
{
remove_from_Folders();
}
void Message::save(Folder& f) //保存到指定Folder中
{
addfol(&f); //更新自身的Folders目录
f.addMsg(this); //向Folder中添加自身
}
void Message::remove(Folder& f) //从指定Folder中移除
{
remfol(&f);
f.remMsg(this);
}
void Message::addfol(Folder* f)
{
folders.insert(f);
}
void Message::remfol(Folder* f)
{
folders.erase(f);
}
void Message::add_to_Folders(const Message& m) //拷贝构造以及拷贝赋值中均需此操作
{
for (auto f : m.folders) //对于每个保存m的Folder
f->addMsg(this); //向其中添加Message自身
}
void Message::remove_from_Folders() //清空保存自身的Folders
{
for (auto f : folders)
f->remMsg(this);
}
//Folder定义
Folder::Folder(const Folder& f) :
messages(f.messages)
{
add_to_Messages(f);
}
Folder& Folder::operator=(const Folder& f)
{
remove_from_Messages();
messages = f.messages;
add_to_Messages(f);
return *this;
}
Folder::~Folder()
{
remove_from_Messages();
}
void Folder::addMsg(Message* m) //添加单个Message元素
{
messages.insert(m);
}
void Folder::remMsg(Message* m) //同上
{
messages.erase(m);
}
void Folder::add_to_Messages(const Folder& f)
{
for (auto m : f.messages) //对于目录中的每一条Message进行单次操作
m->addfol(this); //此处切勿使用save!因为会被save中的f.addMsg(this)循环调用自身
//下方remove同理
}
void Folder::remove_from_Messages() //清空目录中保存的Message
{
for (auto m : messages)
m->remfol(this);
}
int main()
{
Message m1("Hello");
Message m2("World");
Folder f1;
m1.save(f1);
m2.save(f1);
f1.print();
m1.print();
return 0;
}
13.39 & 13.41
StrVec.h
#include<iostream>
#include<string>
#include<memory>
#include<initializer_list>
using namespace std;
class StrVec {
public:
StrVec() :
elements(nullptr), first_free(nullptr), cap(nullptr) {}
StrVec(const initializer_list<string>&);
StrVec(const StrVec&);
StrVec& operator=(const StrVec&);
~StrVec();
void push_back(const string&);
size_t size() const { return first_free - elements; }
size_t capacity() const { return cap - elements; }
string* begin() const { return elements; }
string* end() const { return first_free; }
void reserve(size_t sz);
void resize(size_t, const string& = string()); //声明不要忘记设置缺省值
void print();
private:
static allocator<string> alloc;
void chk_n_alloc() {
if (size() == capacity()) reallocate();
}
pair<string*, string*> alloc_n_copy
(const string*, const string*);
void free();
void reallocate();
string* elements;
string* first_free;
string* cap;
};
StrVec.cpp
#include"test.h"
allocator<string> StrVec::alloc;
StrVec::StrVec(const initializer_list<string>& lst)
{
elements = alloc.allocate(lst.end() - lst.begin());
cap = first_free = uninitialized_copy(lst.begin(), lst.end(), elements);
}
StrVec::StrVec(const StrVec& s)
{
auto newdata = alloc_n_copy(s.begin(), s.end());
elements = newdata.first;
first_free = cap = newdata.second;
}
StrVec& StrVec::operator=(const StrVec& s)
{
auto newdata = alloc_n_copy(s.begin(), s.end());
free();
elements = newdata.first;
first_free = cap = newdata.second;
return *this;
}
StrVec::~StrVec()
{
free();
}
void StrVec::push_back(const string& s)
{
chk_n_alloc();
alloc.construct(first_free++, s);
}
void StrVec::reserve(size_t sz)
{
if (sz > capacity()) {
auto newdata = alloc.allocate(sz);
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 + sz;
}
}
void StrVec::resize(size_t n, const string& s)
{
if (n == size())
return;
if (n < capacity()) {
if (n > size())
for (int i = 0; i < n; ++i)
alloc.construct(first_free++, s);
else
for (auto p = first_free; p != elements + n; )
alloc.destroy(--p);
first_free = elements + n;
}
else {
this->reserve(n + size());
for (int i = 0; i < n; ++i)
alloc.construct(first_free++, s);
}
}
void StrVec::print()
{
for (auto i = elements; i != first_free; ++i)
cout << *i << " ";
}
pair<string*, string*>
StrVec::alloc_n_copy(const string* b, const string* e)
{
auto data = alloc.allocate(e - b);
return { data, uninitialized_copy(b,e,data) };
}
void StrVec::free()
{
if (elements) {
//for (auto p = first_free; p != elements; )
// alloc.destroy(--p);
for_each(elements, first_free, [&](string p) {
alloc.destroy(&p);
});
alloc.deallocate(elements, cap - elements);
}
}
void StrVec::reallocate()
{
auto newcapacity = size() ? 2 * size() : 1;
auto newdata = alloc.allocate(newcapacity);
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 + newcapacity;
}
main.cpp
#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
#include"test.h"
using namespace std;
void test(StrVec& s) {
cout << endl;
s.print();
cout << endl;
cout << "\tCapacity " << s.capacity() << "\tSize " << s.size() << endl;
}
int main()
{
initializer_list<string> list{ "First", "test", };
StrVec s1, s2(list), s3(s2), s4 = s3;
s1 = s2;
test(s1);
s2.push_back("Push_back Test");
test(s2);
s3.reserve(25);
test(s3);
s4.resize(8, "Resize");
test(s4);
s4.resize(3);
test(s4);
s4.resize(1, "Resize");
test(s4);
return 0;
}
13.44
String.h
#include<memory>
#include<algorithm>
using namespace std;
class String {
friend ostream& operator<<(ostream&, const String&);
public:
String() : element(nullptr), first_free(nullptr) {}
String(const char* s) {
size_t sz = strlen(s);
auto newdata = alloc.allocate(sz);
auto dest = newdata;
for (unsigned int i = 0; i != sz; ++i)
alloc.construct(dest++, s[i]);
element = newdata;
first_free = dest;
}
private:
static allocator<char> alloc;
char* element;
char* first_free;
};
main.cpp
#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
#include"test.h"
using namespace std;
ostream& operator<<(ostream& os, const String& s) {
auto c = s.element;
while (c != s.first_free)
os << *c++;
return os;
}
int main()
{
String s1("hello");
cout << s1 << endl;
return 0;
}
13.47
h
#include <iostream>
#include <string>
#include <utility>
#include <memory>
#include <algorithm>
using namespace std;
class String {
friend ostream& operator<<(ostream&, const String&);
public:
String() : element(nullptr), first_free(nullptr) {}
String(const char* s) {
size_t sz = strlen(s);
auto newdata = alloc.allocate(sz);
auto dest = newdata;
for (unsigned int i = 0; i != sz; ++i)
alloc.construct(dest++, s[i]);
element = newdata;
first_free = dest;
}
String(const String& s) {
size_t sz = s.size();
auto data = alloc.allocate(sz);
element = data;
first_free = uninitialized_copy(s.element, s.first_free, data);
cout << "Copy construct" << endl;
}
String& operator=(const String& s) {
size_t sz = s.size();
auto data = alloc.allocate(sz);
element = data;
first_free = uninitialized_copy(s.element, s.first_free, data);
cout << "Copy assignment" << endl;
return *this;
}
size_t size() const { return first_free - element; }
~String() {
if (size())
{
for (auto p = first_free; p != element;)
alloc.destroy(--p);
alloc.deallocate(element, first_free - element);
}
}
private:
static allocator<char> alloc;
char* element;
char* first_free;
};
cpp
#include <iostream>
#include <string>
#include <utility>
#include <memory>
#include <algorithm>
#include <vector>
#include"test.h"
using namespace std;
ostream& operator<<(ostream& os, const String& s) {
auto c = s.element;
while (c != s.first_free)
os << *c++;
return os;
}
int main()
{
String s1("Hello world!");
String s2(s1);
String s3;
s3 = s2;
cout << endl;
cout << s2 << " " << s2.size() << endl;
cout << s3 << " " << s3.size() << endl;
cout << endl;
vector<String> vec;
cout << endl;
//vec.reserve(10);
for (int i = 0; i < 3; ++i) {
vec.push_back("hello");
cout << endl;
}
return 0;
}
默认初始化的vector每次调用push_back的时候,都会重新扩容,这将导致拷贝的次数将在当前添加的元素的基础上将原来容器中所有的元素再次全部重新拷贝一遍。
使用reserve提前声明预先分配空间的大小,可以有效减少拷贝的次数。