c++primer(第五版) 第十三章 拷贝控制习题答案

纯原创    转载请注明出处: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即是调用的自己,将会无限递归死循环
时间: 2024-10-07 18:35:58

c++primer(第五版) 第十三章 拷贝控制习题答案的相关文章

C++ Primer 第五版:第1 章

*****C++ Primer 第五版第1章学习笔记***** *****实验代码在Red Hat 6.6或VS 2013中调试***** *****文章内容依据当前知识撰写,存在认识的局限性***** 1.1 编写一个简单的C++程序 函数:依据我个人理解,C/C++的函数是一个能够完成一个功能的模块. 完整函数的组成: ①返回类型:不一定有返回值,故不一定有返回类型 ②函数名:根据名字标识完成特定功能的模块,必须存在 ③形参列表:可能没有参数传入,不一定存在 ④函数体:一个完整的函数应该是有

C++ Primer 第五版:第2章

*****C++ Primer 第五版第2章学习笔记***** *****实验代码在Red Hat 6.6或VS 2013中调试***** *****文章内容依据当前知识撰写,存在认识的局限性***** 今天学习C++ Primer 的第2章,还没有看完,先写一点看书的心得和笔记. 对象类型决定对象包含的数据和能参与的运算操作,同时还决定了存储空间大小.算术表达式中不要使用char,因为不同机器实现不一样,导致结果不同.单精度计算不一定比双精度快. C++类型不匹配时,是自动进行类型的转换. C

C++Primer第五版习题解答---第一章

C++Primer第五版习题解答---第一章 ps:答案是个人在学习过程中书写,可能存在错漏之处,仅作参考. 作者:cosefy Date: 2022/1/7 第一章:开始 练习1.3 #include<iostream> int main() { std::cout << "hello, world" << std::endl; return 0; } 练习1.4: #include<iostream> int main() { int

C++ Primer 第五版学习笔记

<C++ Primer>第五版中文版学习笔记 ? C++ Primer 第五版学习笔记

《C++ Primer 第五版》练习9.51参考答案

//Date.h #include <map> #include <string> #include <vector> using namespace std; struct Date {         explicit Date(const string & info){//检测输入格式,尝试初始化,若失败则进行errorInit             if(mymap.empty()){               initMap();         

C++ Primer(第五版)学习笔记_9_标准模板库_multimap多重映照容器

C++ Primer(第五版)学习笔记_9_标准模板库_multimap多重映照容器 多重映照容器multimap与map结构基本相同,但由于重复键值存在,所以multimap的元素插入.删除.查找都与map的方法不相同. 1.multimap对象创建.元素插入 插入元素时,需要使用insert()方法和类似pair<string,double>("Jack", 300.5)的元素结构.可以看到,重复的元素是按照插入的先后顺序排序的. #include <iostre

C++ Primer(第五版)学习笔记_5_标准模板库string(2)

C++ Primer(第五版)学习笔记_5_标准模板库string(2) 10.搜索string对象的元素或子串 采用find()方法可查找字符串中的第一个字符元素(char, 用单引号界定)或者子串(用双引号界定):如果查到,则返回下标值(从0开始计数),如果查不到,则返回一个很大的数string:npos(即:4294967295). #include <iostream> #include <stdio.h> #include <string> using nam

C++ Primer(第五版)学习笔记_3_标准模板库vector(2)

C++ Primer(第五版)学习笔记_3_标准模板库vector(2) 欢迎大家阅读参考,如有错误或疑问请留言纠正,谢谢 6.元素的插入 insert()方法可以在vector对象的任意位置前插入一个新的元素,同时,vector自动扩张一个元素空间,插入位置后的所有元素依次向后挪动一个位置. 要注意的是,insert()方法要求插入的位置,是元素的迭代器位置,而不是元素的下标. #include <iostream> #include <vector> using namespa

C++ Primer(第五版)学习笔记_1_标准模板库--快速入门

C++ Primer(第五版)学习笔记_1_标准模板库--快速入门 欢迎大家阅读参考,如有错误或疑问请留言纠正,谢谢 标准模板库(STL)提供三种类型的组件:容器.迭代器和算法,他们都支持泛型程序设计标准. 容器主要有两类:顺序容器和关联容器.顺序容器(vector.list.deque和string等)是一系列元素的有序集合.关联容器(set.multiset.map和multimap)包含查找元素的键值. 迭代器的作用是遍历容器. STL算法库包含四类算法:排序算法.不可变序算法.变序性算法