c++ primer 第十三章習題
練習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++ << ":\n\t" << 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 != '\0') e++;
e++;
auto data = alloc_n_copy(c,e);
elements = data.first;
end = data.second;
}
String::String(const String& s) {
auto data = alloc_n_copy(s.elements, s.end);
elements = data.first;
end = data.second;
}
String& String::operator=(const String& s) {
auto data = alloc_n_copy(s.elements, s.end);
free();
elements = data.first;
end = data.second;
return *this;
}
String::~String() {
free();
}
void String::free() {
if(elements) {
for_each(elements,end,[](char&c){alloc.destroy(&c);});
alloc.deallocate(elements,end-elements);
}
}
練習13.45 符號不一樣 指向物件一個是右值一個是左值。
練習13.46 右左左右
練習13.49
StrVec::StrVec(StrVec&& s) {
auto newData = alloc.allocate(s.size());
auto dest = newData;
auto last = uninitialized_copy(std::move(s.elements),std::move(s.first_free),dest);
elements = dest;
first_free = last;
cap = first_free;
s.elements = s.first_free = s.cap = nullptr;
}
StrVec& StrVec::operator=(StrVec&& s) {
if(this != &s) {
free();
elements = s.elements;
first_free = s.first_free;
cap = s.cap;
s.elements = s.first_free = s.cap = nullptr;
}
}
String::String(String&& s) {
auto newData = alloc.allocate(s.length());
auto last = uninitialized_copy(std::move(s.elements),std::move(s.end),newData);
elements = newData;
end = last;
s.elements = s.end = nullptr;
}
String& String::operator=(String&& s) {
if(this != &s) {
free();
elements = s.elements;
end = s.end;
s.elements = s.end = nullptr;
}
}
Message::Message(Message&& m):contents(std::move(m.contents)) {
remove_folders(m);
}
Message& Message::operator=(Message&& m) {
if(this != &m) {
remove_from_Folders();
contents = std::move(m.contents);
folders = std::move(m.folders);
add_to_Folders(m);
}
return *this;
}
void Message::remove_folders(Message* m) {
folders = std::move(m->folders);
for(auto f : folders) {
f->remMsg(m);
f->addMsg(this);
}
m->folders.clear();
}
13.50 返回右值的時候。
13.51 返回
13.52
HasPtr& operator(HasPtr&& hp) {
use = hp.use;
ps = hp.ps;
i = hp.i;
hp.use = nullptr;
hp.ps = nullptr;
return *this;
}
練習13.53 多了一步賦值
練習13.54 直接呼叫移動賦值
練習13.55
void push_back(string &&t) { data->push_back(std::move(t)); }
練習13.56 遞迴呼叫
練習13.57 正常賦值。