概述
练习13.1 拷贝构造函数是参数为同类对象引用其它参数都有默认值的构造函数。使用其它对象初始化新对象时使用。
练习13.2 应该使用引用参数,否则会陷入循环调用。
练习13.3 拷贝其中的资源与值 拷贝其中的指针对象
练习13.4 书上
练习13.5
HasPtr(HasPtr& hp) {
ps = new string(*hp.ps);
i = hp.i;
}
练习13.6 = 同类对象赋值 每个非static元素相应赋值 未定义拷贝赋值运算符的时候
练习13.7 赋值对应的资源和对象 赋值对应对象
练习13.8
HasPtr& operator=(const HasPtr& a) {
ps = new string(*a.ps);
i = a.i;
}
练习13.9 析构函数释放对象使用的资源并销毁对象的非static数据成员。合成析构函数释放类的成员对象。在用户未定义析构函数的时候会自动合成。
练习13.10 如果data计数减为0的时候释放资源。 销毁对象中的每个成员并且减计数。
练习13.11
~HasPtr() {
delete ps;
}
练习13.12 3次
练习13.13
#include <iostream>
#include <string>
#include <vector>
using namespace std;
struct X
{
int a;
X() {
a = 0;
cout << "X()"<<endl;
}
X(const X& x) {
a = x.a;
cout << "X(const&)"<< a <<endl;
}
X& operator=(X& k) {
a = k.a;
cout <<"operator=(X& k)"<< a <<endl;
}
~X() {
cout << "~X()"<< a <<endl;
}
};
void print(X& a) {
cout << "print(X&a)"<<endl;
}
void prints(X b) {
cout << "print(X b)"<<endl;
}
int main() {
X a;
a.a = 4;
X b(a);
b.a = 5;
X c = a;
c.a = 7;
print(a);
prints(b);
vector<X> v = {a,b,c};
X* k = new X();
delete k;
return 0;
}
练习13.14 相同的内容
练习13.15 会 拷贝构造生成的对象序号不一样 三个不同的序号
练习13.16 没有拷贝构造函数就不会改变,如果接着上题的拷贝构造函数就会。
练习13.17
class numbered
{
public:
int id;
numbered(){id = rand()%100000;};
numbered(numbered& a) {
id = rand()%100000;
}
};
// void f(numbered s) {
//
cout << s.id << endl;
// }
void f(const numbered& s) {
cout << s.id <<endl;
}
int main() {
srand(time(0));
numbered a, b = a, c = b;
f(a);f(b);f(c);
return 0;
}
练习13.18
class Employee
{
int id;
static int count;
string name;
public:
Employee(){id = count;};
Employee(string& n) {
count++;
id = count;
name = n;
}
~Employee(){};
void print() {
cout << id << ' '<< name<<endl;
}
};
int Employee::count = 0;
int main() {
string n("wang");
Employee a(n), b(a);
a.print();
b.print();
return 0;
}
练习13.19 不需要,直接进行默认拷贝即可。
练习13.21 不需要 直接每个默认复制即可
练习13.22
class HasPtr
{
int i;
string* ps;
public:
HasPtr(const string &s = string()):ps(new string(s)), i(0){};
HasPtr(HasPtr& hp) {
ps = new string(*hp.ps);
i = hp.i;
}
HasPtr& operator=(HasPtr&hp){
auto news = new string(*hp.ps);
delete ps;
ps = news;
i = hp.i;
return *this;
}
~HasPtr(){
cout << *ps<<endl;
delete ps;
}
};
练习13.24 内存泄漏 多次析构统一指针的资源
练习13.25 智能指针能够自动析构
练习13.26
StrBlob(StrBlob& a) {
data = make_shared<vector<string>>(new vector<string>(*a.data));
}
StrBlob& operator=(StrBlob& a) {
auto newData = make_shared<vector<string>>(new vector<string>(*a.data));
data = newData;
}
练习13.27
class HasPtr
{
int i;
string* ps;
int *use;
public:
HasPtr(const string &s = string()):ps(new string(s)), i(0),use(new int(1)){};
HasPtr(HasPtr& hp) {
ps = hp.ps;
i = hp.i;
use = hp.use;
++*use;
}
HasPtr& operator=(HasPtr&hp){
++*hp.use;
if(--*use == 0) {
delete ps;
delete use;
}
use = hp.use;
ps = hp.ps;
i = hp.i;
return *this;
}
~HasPtr(){
if(--*use == 0) {
cout << *ps<<endl;
delete ps;
delete use;
}
}
};
练习13.28
class TreeNode
{
public:
TreeNode():count(new int(1)),left(nullptr),right(nullptr){};
TreeNode(TreeNode& n) {
++*n.count;
count = n.count;
value = n.value;
left = n.left;
right = n.right;
}
TreeNode& operator= (TreeNode& n) {
++*n.count;
if(--*count == 0){
delete count;
if(left)
delete left;
if(right)
delete right;
}
count = n.count;
value = n.value;
left = n.left;
right = n.right;
}
~TreeNode(){
if(--*count){
delete count;
if(left){
delete left;
left = nullptr;
}
if(right){
delete right;
right = nullptr;
}
}
}
private:
string value;
int* count;
TreeNode* left;
TreeNode* right;
};
class BinStrTree
{
public:
BinStrTree():root(new TreeNode()){}
BinStrTree(BinStrTree& bst) {
root = new TreeNode(*bst.root);
}
BinStrTree& operator=(BinStrTree& bst) {
auto new_root = new TreeNode(*bst.root);
delete root;
root = new_root;
return *this;
}
~BinStrTree() {
delete root;
}
private:
TreeNode *root;
};
练习13.29 因为内部调用的是std::swap
练习13.30
void swap(HasPtr&a, HasPtr&b) {
swap(a.i,b.i);
swap(a.ps,b.ps);
swap(a.use,b.use);
}
练习13.31
class HasPtr
{
friend void swap(HasPtr&, HasPtr&);
friend bool operator<(const HasPtr&, const HasPtr&);
int i;
string* ps;
int *use;
public:
HasPtr(const string &s = string()):ps(new string(s)), i(0),use(new int(1)){};
HasPtr(const HasPtr& hp) {
ps = hp.ps;
i = hp.i;
use = hp.use;
++*use;
}
void swap(HasPtr& hp) {
using std::swap;
swap(i,hp.i);
swap(ps,hp.ps);
swap(use,hp.use);
cout << "call swap"<<endl;
}
HasPtr& operator=(HasPtr hp){
swap(hp);
return *this;
}
~HasPtr(){
if(--*use == 0) {
cout << *ps<<endl;
delete ps;
delete use;
}
}
};
bool operator<(const HasPtr&a, const HasPtr&b){
return *a.ps < *b.ps;
}
void swap(HasPtr&a, HasPtr&b) {
a.swap(b);
}
练习13.32 指针版本不用分配内存,因此不会。
练习13.33 需要改变所以不能是const,避免拷贝所以是引用
练习13.35 文件夹所属混乱
练习13.36 13.37
#ifndef MYMESSAGE_H
#define MYMESSAGE_H
#include <string>
#include <set>
class Folder;
class Message
{
friend void swap(Message&, Message&);
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&);
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); }
};
class Folder {
friend void swap(Message&, Message&);
friend class Message;
public:
~Folder(); // remove self from Messages in msgs
Folder(const Folder&); // add new folder to each Message in msgs
Folder& operator=(const Folder&); // delete Folder from lhs messages
Folder() = default; // defaults ok
void save(Message&);
// add this message to folder
void remove(Message&); // remove this message from this folder
void debug_print(); // print contents and it's list of Folders,
private:
std::set<Message*> msgs;
// messages in this folder
void add_to_Messages(const Folder&);// add this Folder to each Message
void remove_from_Msgs();
// remove this Folder from each Message
void addMsg(Message *m) { msgs.insert(m); }
void remMsg(Message *m) { msgs.erase(m); }
};
#endif
#include "MyMessage.h"
#include <iostream>
using namespace std;
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 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);
}
Folder::~Folder(){
remove_from_Msgs();
}
Folder::Folder(const Folder& fld):msgs(fld.msgs) {
add_to_Messages(fld);
}
Folder& Folder::operator=(const Folder&f){
remove_from_Msgs();
msgs = f.msgs;
add_to_Messages(f);
return *this;
}
void Folder::save(Message& m) {
msgs.insert(&m);
m.addFldr(this);
}
void Folder::remove(Message& m) {
msgs.erase(&m);
m.remFldr(this);
}
void Folder::debug_print(){
cerr << "Folder contains " << msgs.size() << " messages" << endl;
int ctr = 1;
for (auto m : msgs) {
cerr << "Message " << ctr++ << ":nt" << m->contents << endl;
}
}
void Folder::add_to_Messages(const Folder& f){
for(auto m : f.msgs)
m->addFldr(this);
}
void Folder::remove_from_Msgs(){
while(!msgs.empty())
(*msgs.begin())->remove(*this);
}
练习13.38 没有动态分配的内存因此不需要。
练习13.39 40
#ifndef MYSTRVEC_H
#define MYSTRVEC_H
#include <string>
#include <memory>
#include <initializer_list>
using namespace std;
class StrVec
{
public:
StrVec():elements(nullptr),first_free(nullptr),cap(nullptr){};
StrVec(const StrVec&);
StrVec(initializer_list<string>);
StrVec& operator=(const StrVec&);
~StrVec();
void resize(size_t n, const string& s = "");
void restore(size_t n);
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;}
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* first_free;
string* elements;
string* cap;
};
#endif
#include "MyStrVec.h"
allocator<string> StrVec::alloc;
StrVec::StrVec(const StrVec& s){
auto newData = alloc_n_copy(s.begin(),s.end());
elements = newData.first;
first_free = cap = newData.second;
}
StrVec::StrVec(initializer_list<string> sl) {
auto newData = alloc.allocate(sl.size());
elements = newData;
auto dest = elements;
for(auto s : sl)
alloc.construct(dest++,s);
first_free = cap = dest;
}
StrVec::~StrVec() {
free();
}
StrVec& StrVec::operator=(const StrVec& s) {
auto data = alloc_n_copy(s.begin(),s.end());
free();
elements = data.first;
first_free = cap = data.second;
return *this;
}
void StrVec::reallocate() {
int newSize = size()?2*size():1;
auto newData = alloc.allocate(newSize);
auto dest = newData;
auto elem = elements;
for(size_t i = 0; i != size(); i++)
alloc.construct(dest++, std::move(*elem++));
free();
first_free = dest;
elements = newData;
cap = elements + newSize;
}
void StrVec::free() {
if(elements) {
for(auto p = first_free; p != elements;)
alloc.destroy(--p);
alloc.deallocate(elements,cap-elements);
}
}
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::push_back(const string& s){
chk_n_alloc();
alloc.construct(first_free++,s);
}
void StrVec::resize(size_t n, const string& s) {
auto data = alloc.allocate(2*n);
auto elem = elements;
auto dest = data;
for(size_t i=0; i!= min(size(),n); i++)
alloc.construct(dest++, std::move(*elem++));
for(size_t i = size(); i < n; i++)
alloc.construct(dest++, s);
free();
elements = data;
first_free = dest;
cap = data+2*n;
}
void StrVec::restore(size_t n) {
if (n <= capacity())
return;
else {
auto newData = alloc.allocate(n);
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+n;
}
}
练习13.41 先构造后移动指向的位置。
练习13.42
#include "MyStrVec.h"
#include "MyStrVec.cpp"
#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <unordered_map>
#include <cstring>
#include <exception>
#include <memory>
#include <fstream>
#include <sstream>
using namespace std;
class QueryResult;
class TextQuery{
shared_ptr<StrVec> text;
unordered_map<string, shared_ptr<set<int>>> lines;
public:
TextQuery(ifstream& input) {
text = make_shared<StrVec>();
string s;
int line = 0;
while(getline(input,s)) {
text->push_back(s);
string tmp;
istringstream inw(s);
while(inw >> tmp) {
cout << tmp <<endl;
auto& p = lines[tmp];
if(!p)
p.reset(new set<int>);
p->insert(line);
}
line++;
}
}
QueryResult query(string& s);
};
class QueryResult
{
friend ostream& print(ostream& os, const QueryResult& q);
shared_ptr<set<int>> l;
shared_ptr<StrVec> text;
string word;
public:
QueryResult(string& s, shared_ptr<set<int>> lines ,shared_ptr<StrVec> t) {
l = lines;
word = s;
text = t;
};
set<int>::iterator begin(){return l->begin();};
set<int>::iterator end(){return l->end();}
shared_ptr<StrVec> get_file(){return text;};
};
QueryResult TextQuery::query(string& s) {
auto p = lines.find(s);
if(p == lines.end())
return QueryResult(s, make_shared<set<int>>(), text);
else {
cout << p->second->size()<<endl;
return QueryResult(s, p->second, text);
}
}
ostream& print(ostream& os, const QueryResult& q){
if(q.l->size() == 0)
os << "word "<<q.word<<" not found"<<endl;
else
for(auto i : (*q.l))
cout << "(line "<< i<<") "<<endl;
return os;
}
void runQueries(ifstream& infile) {
TextQuery tq(infile);
do{
cout << "enter the word to look for, or q to quit: ";
string s;
if
(!(cin>>s) || s=="q")break;
print(cout, tq.query(s)) << endl;
}while(true);
}
练习13.43
void StrVec::free() {
if(elements) {
for_each(elements,first_free,[](string& s){alloc.destroy(&s);});
alloc.deallocate(elements,cap-elements);
}
}
练习13.44
#ifndef STRING_H
#define 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 free();
char *elements;
char *end;
static std::allocator<char> alloc;
};
#endif
#include "MyString.h"
#include <iostream>
#include <algorithm>
using namespace std;
allocator<char> String::alloc;
pair<char*, char*> String::alloc_n_copy(const char* b, const char* e) {
auto data = alloc.allocate(e-b);
return {data, uninitialized_copy(b,e,data)};
}
String::String(const char* c) {
auto e = c;
while(*e != '