【足迹C++primer】47、Moving Objects(1)
来源:互联网 发布:sql 定义变量 编辑:程序博客网 时间:2024/05/21 09:27
Moving Objects(1)
* 功能:Moving Objects* 时间:2014年7月17日08:46:45* 作者:cutter_point*/#include<iostream>#include<string>#include<memory>#include<utility>#include<vector>#include<algorithm>#include<set>#include<map>using namespace std;/**************************************Rvalue References**************************************/void fun1(){ int i=42; int &r=i; //引用,r引用了i// int &&rr=i; //错误,不能右值引用一个值// int &r2=i*42; //错误,i*42是一个右值 const int &r3=i*42; //ok,我们可愿意绑定一个右值在const上 int &&rr2=i*42; //吧rr2绑定到结果上 //个人理解就是&单个是引用别名,而&&也是引用但是是const结果}/**************************************Lvalues Persist; Rvalues Are Ephemeral左值长久,右值一瞬**************************************//*Rvalue references refer to objects that are about to be destroyed. Hence, wecan “steal” state from an object bound to an rvalue reference.*//**************************************Variables Are Lvalues**************************************/void fun2(){ int &&rr1=42; //正确,这&&rr1是右值,不能是变化的// int &&rr2=rr1; //错误由于rr1是一个左值,不能引用为右值}/*A variable is an lvalue; we cannot directly bind an rvalue reference to avariable even if that variable was defined as an rvalue reference type*//**************************************The Library move Function**************************************/void fun3(){ int &&rr1=42; //正确,这&&rr1是右值,不能是变化的 int &&rr2=std::move(rr1); //用move吧这rr1转换成左值}/*We can destroy a moved-from object and can assign a new value to it, butwe cannot use the value of a moved-from object.Warning:Code that uses move should use std::move, not move. Doing so avoidspotential name collisions.*//**************************************13.6.2. Move Constructor and Move Assignment**************************************//**Move Operations, Library Containers, and Exceptions*/class StrVec{public: StrVec():elements(nullptr), first_free(nullptr), cap(nullptr){} StrVec(const StrVec&); StrVec(StrVec&&) noexcept; StrVec & operator=(const StrVec&); StrVec & operator=(StrVec&&) noexcept; ~StrVec(); string* begin() const {return elements;} //起始指针 string* end() const {return first_free;} //第一个为空的元素 void push_back(const string&); //拷贝元素进入队列 size_t size() const {return first_free-elements;} //队列存放元素个数 size_t capacity() const {return cap-elements;} //队列存储空间大小private: allocator<string> alloc; string* elements; string* first_free; string* cap; pair<string*, string*> alloc_n_copy(const string*, const string*); void free(); void reallocate(); //重新分配空间并且把原来的元素移动到新空间上 void chk_n_alloc() { if(size() == capacity()) //判断数据长度是否已经达到分配空间的上限 reallocate(); //如果是,那么就重新分配空间 }};/**************************************Move Iterators**************************************/void StrVec::reallocate(){ //分配新空间 auto newcapacity=size() ? 2*size() : 1; auto first=alloc.allocate(newcapacity); auto last=uninitialized_copy(make_move_iterator(begin()), make_move_iterator(end()), first); free(); elements=first; first_free=last; cap=elements+newcapacity;}inlineStrVec::~StrVec(){ free();}inlinepair<string*, string*>StrVec::alloc_n_copy(const string* b, const string* e) //开始和结尾指针{ //要拷贝对象要求的空间大小 auto data=alloc.allocate(e-b); //吧b,e之间的元素拷贝到data中 //返回一个pair pair<string*, string*> p={data, uninitialized_copy(b, e, data)}; return p;}/*void StrVec::reallocate(){ //直接把当前容量扩充到2倍 auto newcapacity=size() ? 2*size() : 1 ; //allocate新内存 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;}*/StrVec &StrVec::operator=(const StrVec &rhs){ //先把要赋值的值拷贝下来 auto data=alloc_n_copy(rhs.begin(), rhs.end()); //避免自己给自己赋值!!! free(); //吧左边的值销毁 //重新赋予给左边 elements=data.first; first_free=cap=data.second; return *this;}StrVec::StrVec(StrVec &&s) noexcept //这个就像移动的是内存空间,然后把指针为空就可以了 :elements(s.elements), first_free(s.first_free), cap(s.cap){ s.elements=s.first_free=s.cap=nullptr;}/**Move-Assignment Operator*/void StrVec::free(){ if(elements) { for(auto p=first_free ; p != elements ; ) alloc.destroy(--p); alloc.deallocate(elements, cap-elements); }}StrVec &StrVec::operator=(StrVec &&rhs) noexcept{ //直接进行赋值,不用特别考虑自己给自己赋值了 if(this != &rhs) //不是自己,不然不做操作 { free(); //清空this内存 elements=rhs.elements; first_free=rhs.first_free; cap=rhs.cap; //让rhs重置 rhs.elements=rhs.first_free=rhs.cap=nullptr; } return *this;}/**************************************A Moved-from Object Must Be Destructible**************************************//*WarningAfter a move operation, the “moved-from” object must remain a valid,destructible object but users may make no assumptions about its value.*//**The Synthesized Move Operations*/struct X{ int i; string s;};struct hasX{ X mem;};void fun4(){ X x, x2=std::move(x); hasX hx, hx2=std::move(hx);}//这些是当类没有自己定义自己的移动构造函数和移动赋值运算符的时候//编译器会自动调用编译器自带的函数/**让默认的move构造函数和move赋值运算符失效*/struct Y{ int i; string s;};struct hasY{ hasY()=default; hasY(hasY&&)=default; Y mem;};void fun5(){ hasY hy, hy2=std::move(hy); //错误:移动构造函数已经被删除了}/*NoteClasses that define a move constructor or move-assignment operator mustalso define their own copy operations. Otherwise, those members are deletedby default.就是定义了那个move的构造之后,也要定义它的operator操作,不然就会被default覆盖删除掉*//**Rvalues Are Moved, Lvalues Are Copied ...*/StrVec getVec(istream &) //这个函数返回一个右值{ StrVec v1; return v1;}void fun6(){ StrVec v1, v2; v1=v2; //v2是一个左值,这是拷贝 v2=getVec(cin); //这个里面getVec得到的是右值,move}/**...But Rvalues Are Copied If There Is No Move Constructor右值也可能是拷贝,如果只是申明move构造函数,而没有定义*/class Foo{public: Foo()=default; Foo(const Foo&); //copy构造函数};Foo::Foo(const Foo &f){}void fun7(){ Foo x; Foo y(x); //拷贝构造x是一个左值 Foo z(std::move(x)); //这里还是拷贝,因为没有move构造函数}/**Copy-and-Swap Assignment Operators and Move*/class HasPtr {friend void swap(HasPtr&, HasPtr&);public: HasPtr(const std::string &s = std::string()):ps(new std::string(s)), i(0) { }// each HasPtr has its own copy of the string to which ps points HasPtr(const HasPtr &p):ps(new std::string(*p.ps)), i(p.i) { } HasPtr(HasPtr &&p) noexcept : ps(p.ps), i(p.i) {p.ps=0;}//HasPtr& operator=(const HasPtr &);//包含赋值操作和交换操作的赋值运算符HasPtr& operator=(HasPtr rhs){swap(*this, rhs); return *this;}//这里注意,HasPtr的参数不是引用,而是一个拷贝参数,对于左值来说是拷贝//但是对于右值来说这就是一个move操作,那么这个操作符既包含copy赋值运算符//和move赋值运算符功能~HasPtr() { delete ps; }private: std::string *ps; int i;};inlinevoid swap(HasPtr &lhs, HasPtr &rhs){using std::swap;swap(lhs.ps, rhs.ps); // swap the pointers, not the string dataswap(lhs.i, rhs.i); // swap the int members}/*using std::string;HasPtr& HasPtr::operator=(const HasPtr &rhs){string *newp = new string(*rhs.ps); // copy the underlying stringdelete ps; // free the old memoryps = newp; // copy data from rhs into this objecti = rhs.i;return *this; // return this object}*/HasPtr f(HasPtr hp) // HasPtr passed by value, so it is copied{HasPtr ret = hp; // copies the given HasPtr// process retreturn ret; // ret and hp are destroyed}void fun8(){ HasPtr hp, hp2; hp=hp2; //这个是拷贝,由于hp2是左值 hp=std::move(hp2); //这个就是move赋值运算了 //自动识别!!!}/**************************************Advice: Updating the Rule of ThreeAll five copy-control members should be thought of as a unit: Ordinarily, if aclass defines any of these operations, it usually should define them all. Aswe’ve seen, some classes must define the copy constructor, copy-assignmentoperator, and destructor to work correctly . Such classestypically have a resource that the copy members must copy. Ordinarily,copying a resource entails some amount of overhead. Classes that define themove constructor and move-assignment operator can avoid this overhead inthose circumstances where a copy isn’t necessary.总的来说就是要定义三个函数:以前是:拷贝构造函数,拷贝赋值运算符,析构函数现在就要:拷贝构造函数,移动构造函数,移动拷贝赋值运算符,析构函数**************************************//**************************************Move Operations for the Message Class**************************************/class Folder;class Message {friend void swap(Message&, Message&);friend class Folder;public: // folders is implicitly initialized to the empty set explicit Message(const string &str = ""):contents(str) { } // copy control to manage pointers to this Message Message(const Message&); // copy constructor //移动构造函数,利用右值move Message(Message&&); void move_Folders(Message *); //吧m中的Folders指针move操作到Message上 Message& operator=(const Message&); // copy assignment //移动赋值运算符 Message& operator=(Message&&); ~Message(); // destructor // add/remove this Message from the specified Folder's set of messages void save(Folder&); void remove(Folder&); void debug_print(); // print contents and it's list of Folders, // printing each Folder as wellprivate: string contents; // actual message text set<Folder*> folders; // Folders that have this Message // utility functions used by copy constructor, assignment, and destructor // add this Message to the Folders that point to the parameter void add_to_Folders(const Message&); // remove this Message from every Folder in folders void remove_from_Folders(); // used by Folder class to add self to this Message's set of Folder's void addFldr(Folder *f) { folders.insert(f); } void remFldr(Folder *f) { folders.erase(f); }};// declaration for swap should be in the same header as Message itselfvoid swap(Message&, Message&);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 // add Folder to rhs messages Folder() { } // 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: 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); }};//move赋值运算符Message& Message::operator=(Message &&rhs){ if(this != &rhs) { remove_from_Folders(); contents=std::move(rhs.contents); move_Folders(&rhs); } return *this;}//move构造函数Message::Message(Message &&m):contents(std::move(m.contents)){ move_Folders(&m);}// move the Folder pointers from m to this Messagevoid Message::move_Folders(Message *m){ folders=std::move(m->folders); //移完指针再把数据移过去 for(auto f : folders) { f->remMsg(m); f->addMsg(this); } m->folders.clear();}void swap(Message &lhs, Message &rhs){using std::swap; // not strictly needed in this case, but good habit// remove pointers to each Message from their (original) respective Foldersfor (set<Folder*>::iterator f = lhs.folders.begin();f != lhs.folders.end(); ++f)(*f)->remMsg(&lhs);for (set<Folder*>::iterator f = rhs.folders.begin();f != rhs.folders.end(); ++f)(*f)->remMsg(&rhs);// swap the contents and Folder pointer setsswap(lhs.folders, rhs.folders); // uses swap(set&, set&)swap(lhs.contents, rhs.contents); // swap(string&, string&)// add pointers to each Message to their (new) respective Foldersfor (set<Folder*>::iterator f = lhs.folders.begin();f != lhs.folders.end(); ++f)(*f)->addMsg(&lhs);for (set<Folder*>::iterator f = rhs.folders.begin();f != rhs.folders.end(); ++f)(*f)->addMsg(&rhs);}Message::Message(const Message &m): contents(m.contents), folders(m.folders){ add_to_Folders(m); // add this Message to the Folders that point to m}Message& Message::operator=(const Message &rhs){// handle self-assignment by removing pointers before inserting them remove_from_Folders(); // update existing Folders contents = rhs.contents; // copy message contents from rhs folders = rhs.folders; // copy Folder pointers from rhs add_to_Folders(rhs); // add this Message to those Folders return *this;}Message::~Message(){ remove_from_Folders();}// add this Message to Folders that point to mvoid Message::add_to_Folders(const Message &m){for (set<Folder*>::iterator f = m.folders.begin();f != m.folders.end(); ++f) // for each Folder that holds m (*f)->addMsg(this); // add a pointer to this Message to that Folder}// remove this Message from the corresponding Foldersvoid Message::remove_from_Folders(){for (set<Folder*>::iterator f = folders.begin();f != folders.end(); ++f) // for each pointer in folders(*f)->remMsg(this); // remove this Message from that Folderfolders.clear(); // no Folder points to this Message}void Folder::add_to_Messages(const Folder &f){for (set<Message*>::iterator msg = f.msgs.begin();msg != f.msgs.end(); ++msg)(*msg)->addFldr(this); // add this Folder to each Message}Folder::Folder(const Folder &f) : msgs(f.msgs){ add_to_Messages(f); // add this Folder to each Message in f.msgs}Folder& Folder::operator=(const Folder &f){ remove_from_Msgs(); // remove this folder from each Message in msgsmsgs = f.msgs; // copy the set of Messages from f add_to_Messages(f); // add this folder to each Message in msgs return *this;}Folder::~Folder(){ remove_from_Msgs();}void Folder::remove_from_Msgs(){ while (!msgs.empty()) (*msgs.begin())->remove(*this);}void Message::save(Folder &f){ folders.insert(&f); // add the given Folder to our list of Folders f.addMsg(this); // add this Message to f's set of Messages}void Message::remove(Folder &f){ folders.erase(&f); // take the given Folder out of our list of Folders f.remMsg(this); // remove this Message to f's set of Messages}void Folder::save(Message &m){ // add m and add this folder to m's set of Folders msgs.insert(&m); m.addFldr(this);}void Folder::remove(Message &m){ // erase m from msgs and remove this folder from m msgs.erase(&m); m.remFldr(this);}void Folder::debug_print(){ cerr << "Folder contains " << msgs.size() << " messages" << endl; int ctr = 1; for (set<Message*>::iterator m = msgs.begin();m != msgs.end(); ++m) { cerr << "Message " << ctr++ << ":\n\t" << (*m)->contents << endl;}}void Message::debug_print(){ cerr << "Message:\n\t" << contents << endl; cerr << "Appears in " << folders.size() << " Folders" << endl;}int main(){ return 0;}
PS:代码全在,里面各种注释,我一后还是这样写吧,除了一些特殊的感悟自己写出来,然后大部分大家直接在代码中学习,这样避免了,看那些文字的烦躁,和那些看文字的无聊!!!
今天早上出去溜达一圈,回来早餐吃泡面,尼玛,我真是服了,第一次早上吃泡面,然后把面什么的放碗里,最后把调料又放回了袋子里,我的天!!!
0 0
- 【足迹C++primer】47、Moving Objects(1)
- 【足迹C++primer】47、Moving Objects(2)
- 【足迹C++primer】42、拷贝、赋值与销毁(1)
- 【足迹C++primer】表达式求值
- 【足迹C++primer】33、再探迭代器
- 【足迹C++primer】39、动态内存与智能指针(1)
- 【足迹C++primer】38、关联容器操作(1)
- 【足迹C++primer】30、概述(泛型算法)
- 【足迹C++primer】15、定义抽象数据类型
- 【足迹C++primer】21、IO类
- 【足迹C++primer】22、文件输入输出
- 【足迹C++primer】23、string流
- 【足迹C++primer】24、顺序容器概述
- 【足迹C++primer】25、容器库概览
- 【足迹C++primer】26、顺序容器操作
- 【足迹C++primer】29、容器适配器
- 【足迹C++primer】32、定制操作_1
- 【足迹C++primer】32、定制操作_2
- Rewards - #256 (Div. 2) A (448A)水题
- C# 文件夹以及文件复制
- 支操作符称为开关。
- SQL联合查询(内联、左联、右联、全联)的语法
- 读整数,直到输入0。终止输入后程序应报告 输入的偶数(不包括0)总个数以及偶数的平 均值,奇数的个数及平均值。
- 【足迹C++primer】47、Moving Objects(1)
- 面试算法(四十一)和为s的两个数字VS和为s的连续正数序列
- freemarker函数使用
- HDU3181 Greatest Naruto Army
- OC---第六讲作业
- C/C++内存管理(4)
- hdu1572(下沙小面的(2))(深搜找最短路)
- iOS音频播放 (二):AudioSession
- com关于引用计数