拷贝控制习题答案
Posted Kuro同学
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了拷贝控制习题答案相关的知识,希望对你有一定的参考价值。
纯原创 转载请注明出处:http://blog.csdn.net/axuan_k
13.2 13.3 13.4 13.5
#include<iostream>
using namespace std;
class Point{
int a;
};
Point global; //13.4
Point foo_bar(Point arg) //1
{
Point local = arg, *heap = new Point(global); //2,3
*heap = local;
Point pa[ 4 ] = { local, *heap }; //4,5
return *heap; //6
}
class HasPtr{
public:
HasPtr(const string&s=string()):ps(new string(s)),i(0){}
HasPtr(const HasPtr& hp):ps(new string(*hp.ps)),i(hp.i){} // 13.5
private:
string *ps;
int i;
};
int main(){
// 13.2
// 拷贝构造函数的参数如果是实参,那就需要在调用它的时候复制 原对象给它,
// 而这个复制过程又需要调用拷贝构造函数才能完成,如此无限循环
// 13.3
// StrBlob中智能share指针指向的对象的use_count会+1
// 而StrBlobPtr中智能weak指针指向的use_count不会变
// 是share指针和weak指针的性质决定的
return 0;
}
13.6 13.7 13.8
#include<iostream>
using namespace std;
class HasPtr{
public:
HasPtr(const string&s=string()):ps(new string(s)),i(0){}
HasPtr(const HasPtr& hp):ps(new string(*hp.ps)),i(hp.i){}
HasPtr& operator=(const HasPtr& hp){ //13.8
ps=new string(*hp.ps);
i=hp.i;
return *this;
}
private:
string *ps;
int i;
};
int main(){
// 13.6
// 拷贝赋值运算符: operator=
// 当需要进行同类中对象的赋值时使用它
// 完成 将右侧所有非static的成员赋予左侧运算对象的对应成员
// 当用户未定义自己的拷贝赋值运算符时
// 13.7
// StrBlob赋值时 被赋值的StrBlob指向容器的use_count-1,赋值一方StrBlob指向容器的use_count+1
// StrBlobPtr的两侧指向容器的use_count都不会变
return 0;
}
13.9 13.10 13.11 13.12 13.13
#include<iostream>
#include<vector>
using namespace std;
class HasPtr{
public:
HasPtr(const string&s=string()):ps(new string(s)),i(0){}
HasPtr(const HasPtr& hp):ps(new string(*hp.ps)),i(hp.i){}
HasPtr& operator=(const HasPtr& hp){
ps=new string(*hp.ps);
i=hp.i;
return *this;
}
~HasPtr(){delete ps;} //13.11
private:
string *ps;
int i;
};
struct X{
X(){cout<<"X()"<<endl;}
X(const X& x){cout<<"X(const X& x)"<<endl;}
X& operator=(const X& x){cout<<"X& operator=(const X& x)"<<endl; return *this;}
~X(){cout<<"~X()"<<endl;}
};
void func(const X& a,const X b){
vector<X>vec;
cout<<"1111111111"<<endl;
vec.push_back(a);
cout<<"1111"<<endl;
vec.push_back(b);
cout<<1111<<endl;
}
int main(){
// 13.9
// 析构函数释放对象使用的资源,并销毁对象的非static成员
// 合成析构函数可以用来阻止对象被销毁,否则函数体为空
// 当用户未定义对应类的析构函数时
// 13.10
// StrBlob指向容器的use_count会-1,如果该容器use_count为0则会被销毁
// 而StrBlobPtr指向容器的use_count不会变
// 13.12
// 共三次
// bool fcn(const Sales_data *trans, Sales_data accum)
//对象accum函数结束时销毁 +1次
//{
// Sales_data item1(*trans), item2(accum);
// 对象item1 item2函数结束时销毁 +2次
// return item1.isbn() != item2.isbn();
//}
// 13.13
X* a=new X;
X* c=a;
*c=*a;
X d(*a);
func(*a,d);
return 0;
}
13.14 13.15 13.16 13.17
#include<iostream>
#include<vector>
using namespace std;
class numbered{
public:
numbered():mysn(get_id()){}
numbered(const numbered& x):mysn(get_id()){}
int get_id(){return ++num;}
int mysn;
static int num;
};
int numbered::num=0;
void f(const numbered& x){cout<<x.mysn<<endl;}
int main(){
// 13.14
// 输出全都是1,a是默认构造函数创建的,b,c是拷贝构造函数创建的
numbered a,b=a,c=b;
f(a),f(b),f(c);
// 13.15
// 会 输出4 5 6
// b,c都是通过我们自己定义的拷贝构造函数创建的
// 当abc传参数给x时又会调用拷贝构造函数
// 13.16
// 会 输出1 2 3
// 当f的参数为引用时,就不会调用拷贝构造函数 num也就不会+1
// 13.17
return 0;
}
13.18 13.19 13.20
#include<iostream>
#include<vector>
using namespace std;
class Employee{ //13.18
public:
Employee()=default;
Employee(const string& s):name(s),id(get_id()){}
Employee(const Employee& e)=delete;
Employee& operator=(const Employee& e)=delete;
private:
string name;
int id;
static int num;
const int get_id()const{return ++num;}
};
int Employee::num=0;
int main(){
// 13.19
// 需要 因为每个对象都应该有一个独立的id
// 默认合成的拷贝构造函数和拷贝赋值函数都会复制id,不应该有拷贝和赋值的操作
// 13.20
// TextQuery和QueryResult所有成员(包括智能指针和容器)都将被拷贝
return 0;
}
13.21
#ifndef MY_CLASS
#define MY_CLASS
#include<iostream>
#include<sstream>
#include<fstream>
#include<map>
#include<set>
#include<vector>
#include<string>
#include<memory>
class QueryResult;
std::ostream& print(std::ostream&, const QueryResult&);
class TextQuery {
public:
//typedef
using line_no = std::vector<std::string>::size_type;
//constructor
TextQuery(std::ifstream&);
//Query function
QueryResult query(const std::string&) const;
TextQuery(const TextQuery&) = delete;
TextQuery& operator=(const TextQuery&) = delete;
private:
//data members
std::shared_ptr<std::vector<std::string>> in_file;
std::map<std::string, std::shared_ptr<std::set<line_no>>> word_occr;
};
//TextQuery constructor
TextQuery::TextQuery(std::ifstream& input) : in_file(new std::vector<std::string>) {
for (std::string text; getline(input, text); in_file->push_back(text)) {
int cur_line_no = in_file->size() + 1;
std::string word;
for (std::istringstream line(text); line >> word; ) {
auto &line_nums = word_occr[word];
if (!line_nums)
line_nums.reset(new std::set<TextQuery::line_no>);
line_nums->insert(cur_line_no);
}
}
}
class QueryResult {
friend std::ostream& print(std::ostream&, const QueryResult&);
public:
//constructor
QueryResult(std::string s,
std::shared_ptr<std::vector<std::string>> f,
std::shared_ptr<std::set<TextQuery::line_no>> l)
: sought(s), file(f), lines(l) { }
QueryResult(const QueryResult&) = delete;
QueryResult& operator=(const QueryResult&) = delete;
QueryResult(QueryResult &&) noexcept = default; //!! here!!
//member functions
std::set<TextQuery::line_no>::iterator begin() { return lines->begin(); }
std::set<TextQuery::line_no>::iterator end() { return lines->end(); }
std::shared_ptr<std::vector<std::string>> get_file() { return file; }
private:
//data members
std::string sought; //word sought by this query
std::shared_ptr<std::vector<std::string>> file; //file we are searching in
std::shared_ptr<std::set<TextQuery::line_no>> lines; //lines sought is found on
};
QueryResult TextQuery::query(const std::string& s) const {
static std::shared_ptr<std::set<line_no>> nodata(new std::set<line_no>);
auto found = word_occr.find(s);
if (found == word_occr.end())
return QueryResult(s, in_file, nodata);
else
return QueryResult(s, in_file, found->second);
}
std::ostream& print(std::ostream& out, const QueryResult& qr) {
out << qr.sought << " : " << qr.lines->size() << std::endl;
return out;
}
#endif
13.24 13.25 13.26
#include<iostream>
#include<vector>
#include<string>
#include<memory>
#include<stdexcept>
using namespace std;
class StrBlob
{
public:
typedef vector<string>::size_type size_type;
StrBlob():data(make_shared<vector<string>>()){}
StrBlob(initializer_list<string>il):data(make_shared<vector<string>>(il)){}
StrBlob(const StrBlob& sb):data(make_shared<vector<string>>(*sb.data)){} //13.26
StrBlob& operator=(const StrBlob& sb){ //13.26
data=make_shared<vector<string>>(*sb.data); //拷贝赋值函数不需要定义局部临时变量 shared_ptr特性
return *this;
}
size_type size()const{return data->size();}
bool empty(){return data->empty();}
void push_back(const string& str){data->push_back(str);}
void pop_back(){
check(0,"pop_back on empty StrBlob");
data->pop_back();
}
string& front()const
{
check(0,"front on empty StrBlob");
return data->front();
}
string& back()const
{
check(0,"back on empty StrBlob");
return data->back();
}
private:
shared_ptr<vector<string>> data;
void check(size_type i,const string& msg)const{
if(i>=data->size())
throw out_of_range(msg);
}
};
int main(){
// 13.24
// HasPtr的成员ps指向的string的内存是动态分配的,如果用合成的析构函数,那么那段内存就不会被释放,造成内存泄露
// 13.25
// 我们想让StrBlob像一个值,那么每个StrBlob都应该有一块独立的内存,
// 而合成版本的拷贝构造函数和拷贝赋值运算符不会分配内存,需要我们自己定义函数来分配内存
// 又因为StrBlob的唯一成员是智能指针,当指针指向对象的use_count为1时自动销毁内存,所有不需要我们来手动销毁动态内存.
return 0;
}
13.27 13.28
#include<iostream>
#include<vector>
using namespace std;
class HasPtr{ //13.27
public:
HasPtr():ps(new string()),use(new int(1)){}
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){
++(*hp.use);
}
HasPtr& operator=(const HasPtr& hp){
++(*(this->use));
--(*(this->use));
if(this->use==0){
delete (this->ps);
delete (this->use);
}
this->ps=hp.ps;
this->i=hp.i;
this->use=hp.use;
return *this;
}
~HasPtr(){
--(*(this->use));
if(this->use==0){
delete (this->ps);
delete (this->use);
}
}
private:
string *ps;
int i;
int* use;
};
class TreeNode{ //行为像指针 //13.28
public:
TreeNode():value(""),count(new int(1)),left(nullptr),right(nullptr){} //left,right指向的内存应该在其他函数内分配
TreeNode(const TreeNode& tr)
:value(tr.value),count(tr.count),left(tr.left),right(tr.right){
++(*tr.count);
}
TreeNode& operator=(const TreeNode& tr){
++(*tr.count);
--(*this->count);
if(*(this->count)==0){
delete this->count;
delete this->left; //可以delete空指针
delete this->right;
}
this->value=tr.value;
this->count=tr.count;
this->left=tr.left;
this->right=tr.right;
return *this;
}
~TreeNode(){
--(*this->count);
if(*(this->count)==0){
delete this->count;
delete this->left;
delete this->right;
}
}
private:
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){
TreeNode* tr=new TreeNode(*bst.root);
delete this->root;
this->root=tr;
return *this;
}
~BinStrTree(){
delete this->root;
}
private:
TreeNode *root;
};
int main(){
BinStrTree bst,bst2;
bst2=bst;
BinStrTree bst3=bst;
return 0;
}
11.29 11.30 11.31 11.32
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
class HasPtr{
friend void swap(HasPtr& lhs,HasPtr& rhs){
// 11.29
// 该swap内部调用的并不是自己,而是std::swap
// 同时这些swap的参数类型也各不相同,证明不是递归调用自己
cout<<"call swap(HasPtr&,HasPtr&)"<<endl;
std::swap(lhs.ps,rhs.ps);
std::swap(lhs.i,rhs.i);
}
friend bool operator<(const HasPtr& lhs,const HasPtr& rhs){
return *lhs.ps<*rhs.ps;
}
public:
HasPtr(const string&s=string()):ps(new string(s)),i(0){}
HasPtr(const HasPtr& hp):ps(new string(*hp.ps)),i(hp.i){}
HasPtr& operator=(const HasPtr& hp){
string* newp=new string(*hp.ps);
delete this->ps;
ps=newp;
i=hp.i;
return *this;
}
~HasPtr(){delete ps;}
//private:
string *ps;
int i;
};
int main(){
// 11.30
HasPtr a("aaaaaaa");
HasPtr c("sssssss");
swap(a,c);
// 11.31
vector<HasPtr>vec{c,a};
vec.push_back(HasPtr("gggggggggg"));
vec.push_back(HasPtr("wwwwwwwwww"));
vec.push_back(HasPtr("dddddddddd"));
sort(vec.begin(),vec.end());
// 11.32
// 本质上值版本的swap就是为了避免临时的内存分配,从而提高性能
// 而指针版本的类在赋值的过程中本来就不需要分配临时内存,所以指针版本不会得到益处.
return 0;
}
13.33-----13.38
//Folder_and_Message.h
#include <string>
#include <set>
class Folder;
//13.34
class 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();
// 13.37
void addFldr(Folder *f) { folders.insert(f); }
void remFldr(Folder *f) { folders.erase(f); }
};
// 13.36
class Folder {
friend class Message;
public:
Folder(){};
Folder(const Folder &);
Folder& operator=(const Folder &);
~Folder();
private:
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); }
};
</pre><pre name="code" class="cpp">
//Folder_and_Message.cpp
#include"Folder.h"
using namespace std;
Message::Message(const Message& msg)
:contents(msg.contents),folders(msg.folders){add_to_Folders(msg);}
Message& Message::operator=(const Message& msg){
this->remove_from_Folders();
contents=msg.contents;
folders=msg.folders;
this->add_to_Folders(msg);
return *this;
}
Message::~Message(){
remove_from_Folders();
}
void Message::save(Folder& f){
f.addMsg(this);
folders.insert(&f);
}
// 13.33
// 不用Folder:避免直接拷贝一个对象,提高性能
// 不加const:在该函数中会对Folder的对象进行insert操作,需要改变它
void Message::remove(Folder& f){
f.remMsg(this);
folders.erase(&f);
}
void Message::add_to_Folders(const Message& msg){
for(auto f:msg.folders)
f->addMsg(this);
}
void Message::remove_from_Folders(){
for(auto f:this->folders)
f->remMsg(this);
}
//-------------------------------------------------
Folder::Folder(const Folder& f)
:msgs(f.msgs){add_to_Message(f);}
Folder& Folder::operator=(const Folder& f){
this->remove_from_Message();
msgs=f.msgs;
this->add_to_Message(f);
return *this;
}
Folder::~Folder(){remove_from_Message();}
void Folder::add_to_Message(const Folder& f){
for(auto i:f.msgs)
i->addFldr(this);
}
void Folder::remove_from_Message(){
for(auto i:this->msgs)
i->remFldr(this);
}
// 13.35
// 书中原话:当我们拷贝一个message时,得到的副本应该与原message出现在相同的Folder中
// 对新拷贝的message对象,如果用的是默认合成拷贝构造函数
// 则新的message不会添加进入那些包含原message的folder中
// 13.38
//@Mooophy: The copy and swap is an elegant way when working with dynamicly allocated memory. In the Message class ,
// nothing is allocated dynamically. Thus using this idiom makes no sense and will make it more complicated to
// implement due to the pointers that point back.
//当涉及到动态分配内存时,拷贝并交换是一个完成该功能的精简的方式.
//但是在Message类中,并未涉及到动态分配内存,这种方法并不会产生任何益处,
//同时还会因为很多指针操作让程序变得更复杂难难以实现
13.39 13.40 13.41 13.43
//StrVec.h
#include<iostream>
#include<string>
#include<vector>
using namespace std;
class StrVec{
public:
StrVec():elements(nullptr),first_free(nullptr),cap(nullptr){}
StrVec(initializer_list<string>);
StrVec(const StrVec&);
StrVec& operator=(const StrVec&);
~StrVec(){free();}
void push_back(const string&);
size_t size()const{return first_free-elements;}
size_t capcity()const{return cap-elements;}
string* begin()const{return elements;}
string* end()const {return first_free;}
void reserve(size_t);
void resize(size_t,const string&);
void resize(size_t);
private:
static allocator<string>alloc;
void chk_n_alloc(){if(size()==capcity())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"StrVec.h"
#include<algorithm>
allocator<string>StrVec::alloc;
void StrVec::push_back(const string& s){
chk_n_alloc();
alloc.construct(first_free++,s);
//13.41
//每次创造对象应该在first_free所指向的位置创造
//如果用前置递增则第一次push_back会浪费一个单位的内存没有被构造,同时first_free将指向容器内最后一个有对象的位置
}
pair<string*,string*> StrVec::alloc_n_copy(const string* bg,const string* ed){
auto data=alloc.allocate(ed-bg);
return {data,uninitialized_copy(bg,ed,data)};
}
void StrVec::free(){
if(elements){
for(auto p=first_free;p!=elements;)
alloc.destroy(--p);
alloc.deallocate(elements,cap-elements);
}
}
void free2(){ //13.43 此版本更好 不用考虑下标越界,更加简洁
for_each(elements,first_free,[](string& r){alloc.destroy(&r);});
}
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;
}
void StrVec::reallocate(){
auto newcapcity=size()?(size()*2):1;
auto newdata=alloc.allocate(newcapcity);
auto old_e=elements;
auto dest=newdata;
for(size_t i=0;i<size();++i)
alloc.construct(dest++,std::move(*old_e++));
free();
elements=newdata;
first_free=dest;
cap=elements+newcapcity;
}
//13.39
void StrVec::reserve(size_t n){
if(n>capcity()){
auto newcapcity=n;
auto newdata=alloc.allocate(newcapcity);
auto old_e=elements;
auto dest=newdata;
for(size_t i=0;i<size();++i)
alloc.construct(dest++,std::move(*old_e++));
free();
elements=newdata;
first_free=dest;
cap=elements+newcapcity;
}
}
void StrVec::resize(size_t n){
resize(n,string());
}
void StrVec::resize(size_t n,const string& str){
auto dest=elements+n;
if(n<size()){
while(first_free!=dest)
alloc.destroy(--first_free);
}
else{
if(n>capcity())reallocate();
while(first_free!=dest)
alloc.construct(first_free++,str);
}
}
StrVec::StrVec(initializer_list<string>lst){ //13.40
auto newdata=alloc_n_copy(lst.begin(),lst.end());
elements=newdata.first;
first_free=cap=newdata.second;
}
//main.cpp
#include <iostream>
#include<vector>
#include"StrVec.h"
using namespace std;
int main()
{
// 13.39
StrVec sv({"aa","bbb","cccc","gggg"}); //13.40
sv.push_back("ssssssss");
sv.push_back("ddddd");
sv.push_back("eeeeee");
cout<<sv.size()<<" "<<sv.capcity()<<endl;
sv.reserve(20);
cout<<sv.size()<<" "<<sv.capcity()<<endl;
sv.resize(12,"asd");
cout<<sv.size()<<" "<<sv.capcity()<<endl;
sv.resize(10);
cout<<sv.size()<<" "<<sv.capcity()<<endl;
return 0;
}
13.44
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
class ChVec{
public:
ChVec():elements(nullptr),cap(nullptr){}
ChVec(const char* ch,size_t len);
ChVec(const ChVec&);
ChVec& operator=(const ChVec&);
~ChVec(){free();}
size_t capacity(){return cap-elements;}
void print(){for(char* p=elements;p<cap;p++)cout<<*p;cout<<endl;}
private:
allocator<char>alloc;
char* elements;
char* cap;
void free(){
if(elements){
size_t len=cap-elements;
while(cap!=elements)
alloc.destroy(--cap);
alloc.deallocate(elements,len);
}
}
pair<char*,char*> alloc_n_copy(const char* st,const char* ed){
char* data=alloc.allocate(ed-st);
return {data,uninitialized_copy(st,ed,data)};
}
};
ChVec::ChVec(const char* ch,size_t len){
auto newdata=alloc_n_copy(ch,ch+len);
elements=newdata.first;
cap=newdata.second;
}
ChVec::ChVec(const ChVec& cv){
auto newdata=alloc_n_copy(cv.elements,cv.cap);
elements=newdata.first;
cap=newdata.second;
}
ChVec& ChVec::operator=(const ChVec& cv){
auto newdata=alloc_n_copy(cv.elements,cv.cap);
free();
elements=newdata.first;
cap=newdata.second;
return *this;
}
int main(){
ChVec cv1;
cv1.print();
cout<<cv1.capacity()<<endl;
char* str="aaaaaaaaaaaaaassdd";
ChVec cv(str,strlen(str));
cv.print();
cout<<cv1.capacity()<<endl;
return 0;
}
13.45 -----13.48
#include<iostream>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
class String{
public:
String():elements(nullptr),cap(nullptr){}
String(const char* ch,size_t len);
String(const String&);
String& operator=(const String&);
~String(){free();}
size_t capacity(){return cap-elements;}
void print(){for(char* p=elements;p<cap;p++)cout<<*p;cout<<endl;}
private:
allocator<char>alloc;
char* elements;
char* cap;
void free(){
if(elements){
size_t len=cap-elements;
while(cap!=elements)
alloc.destroy(--cap);
alloc.deallocate(elements,len);
}
}
pair<char*,char*> alloc_n_copy(const char* st,const char* ed){
char* data=alloc.allocate(ed-st);
return {data,uninitialized_copy(st,ed,data)};
}
};
String::String(const char* ch,size_t len){
auto newdata=alloc_n_copy(ch,ch+len);
elements=newdata.first;
cap=newdata.second;
}
String::String(const String& cv){
auto newdata=alloc_n_copy(cv.elements,cv.cap);
elements=newdata.first;
cap=newdata.second;
cout<<"String(const String& cv)"<<endl; // 13.47
}
String& String::operator=(const String& cv){
auto newdata=alloc_n_copy(cv.elements,cv.cap);
free();
elements=newdata.first;
cap=newdata.second;
cout<<"operator=(const String& cv)"<<endl; // 13.47
return *this;
}
int f(){return 1;}
int main(){
// 13.45
// 左值引用:绑定左值(通常称为变量)
// 右值引用:绑定右值(通常是字面常量或者即将销毁的变量)
// 13.46
vector<int>vi(100);
int&& r1=f(); //函数返回临时变量
int& r2=vi[0]; //vi[0]是一个变量
int& r3=r1; //r1是一个表达式(左值)
int&& r4=vi[0]*f(); //乘积为临时变量
// 13.48
vector<String>vec;
char* s="aaaaa";
String str(s,strlen(s));
cout<<"------------"<<endl;
vec.push_back(String("ssssss",7));
cout<<"------------"<<endl;
vec.push_back(String("sssddd",7));
cout<<"------------"<<endl;
vec.push_back(String("asd",3));
cout<<"------------"<<endl;
vec.push_back(String("asdd",4));
return 0;
}
13.49
//StrVec
StrVec::StrVec( StrVec&& sv)
:elements(sv.elements),first_free(sv.first_free),cap(sv.cap){
sv.cap=sv.first_free=sv.elements=nullptr;
}
StrVec& StrVec::operator=(StrVec&& sv){
if(this!=&sv){
free();
elements=sv.elements;
first_free=sv.first_free;
cap=sv.cap;
sv.cap=sv.first_free=sv.elements=nullptr;
}
return *this;
}
//String
String::String(String&& st):elements(st.elements),cap(st.cap){
st.elements=st.cap=nullptr;
}
String& String::operator=(String&& st){
if(&st!=this){
free();
elements=st.elements;
cap=st.cap;
st.elements=st.cap=nullptr;
}
return *this;
}
//Message
void Message::move_folder(Message* msg){
folders=std::move(msg->folders);
for(auto f:folders){
f->remMsg(msg);
f->addMsg(this);
}
(msg->folders).clear();
}
Message::Message(Message&& msg):contents(std::move(msg.contents)){
move_folder(&msg);
}
Message& Message::operator=(Message&& msg){
if(this!=&msg){
remove_from_Folders();
contents=std::move(msg.contents);
move_folder(&msg);
}
return *this;
}
13.51----13.54
#include<iostream>
#include<string>
using namespace std;
class HasPtr{
friend void swap(HasPtr& l,HasPtr& r){
std::swap(l.ps,r.ps);
std::swap(l.i,r.i);
}
public:
HasPtr(const string& s=string()):ps(new string(s)),i(0){cout<<"HasPtr(const string& s=string())"<<endl;}
HasPtr(const HasPtr& p):ps(new string(*p.ps)),i(p.i){cout<<"HasPtr(const HasPtr& p)"<<endl;}
~HasPtr(){delete ps;cout<<"~HasPtr()"<<endl;}
HasPtr(HasPtr &&p)noexcept : ps(p.ps),i(p.i){p.ps=0;cout<<"HasPtr(HasPtr &&p)"<<endl;}
HasPtr& operator=(HasPtr rhs){
swap(*this,rhs);
cout<<"HasPtr& operator=(HasPtr rhs)"<<endl;
return *this;
}
// 13.53
//HasPtr& operator=(HasPtr& rhs){
// delete ps;
// swap(*this,rhs);
// cout<<"HasPtr& operator=(HasPtr& rhs)"<<endl;
// return *this;
// }
// HasPtr& operator=(HasPtr&& rhs){
// ps=std::move(rhs.ps);
// i=std::move(rhs.i);
// rhs.ps=nullptr;
// cout<<"HasPtr& operator=(HasPtr&& rhs)"<<endl;
// return *this;
// }
private:
string* ps;
int i;
};
int main(){
// 13.51
// 因为函数返回的是一个右值,是一个即将销毁的智能指针
// 因为unique_ptr有一个移动构造函数:unique_ptr::unique_ptr(unique_ptr && src);
// (参数为一个右值,也就是把函数返回的右值移动到新的unique_ptr上);
// 13.52
HasPtr hp,hp2;
// 调用两次构造函数
cout<<"--------------------"<<endl;
hp=hp2;
// 调用一次拷贝构造函数(复制给operator=的形参)
// 调用一次operator=
// 一次析构函数(销毁形参对象)
cout<<"--------------------"<<endl;
hp=std::move(hp2);
// 调用一次移动构造函数
// 一次operator= (形参通过移动构造函数得到)
// 3次析构
// 13.54
// error: ambiguous overload for 'operator=' (operand types are 'HasPtr' and 'std::remove_reference<HasPtr&>::type { aka HasPtr }')
// hp1 = std::move(*pH);
return 0;
}
13.55------13.58
#include<iostream>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
// 13.58
class Foo{
public:
Foo sorted()&&;
Foo sorted()const & ;
private:
vector<int> data;
};
Foo Foo::sorted()&{
sort(data.begin(),data.end());
return *this;
}
// 13.57 函数内部调用&&版本 没有问题
Foo Foo::sorted()const&{
return Foo(*this)sorted();
};
// 13.55
void push_back(string&& s){
data->push_back(std::move(s));
}
// 13.56
//ret是临时创建的变量(左值) ,所以调用sorted即是调用的自己,将会无限递归死循环
以上是关于拷贝控制习题答案的主要内容,如果未能解决你的问题,请参考以下文章
Thing in java 第四章,控制执行流程,练习题答案