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, we
can “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 a
variable 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, but
we cannot use the value of a moved-from object.
Warning:
Code that uses move should use std::move, not move. Doing so avoids
potential 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;
} inline
StrVec::~StrVec()
{
free();
} inline
pair<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
**************************************/
/*
Warning
After 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); //错误:移动构造函数已经被删除了
} /*
Note
Classes that define a move constructor or move-assignment operator must
also define their own copy operations. Otherwise, those members are deleted
by 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;
}; inline
void swap(HasPtr &lhs, HasPtr &rhs)
{
using std::swap;
swap(lhs.ps, rhs.ps); // swap the pointers, not the string data
swap(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 string
delete ps; // free the old memory
ps = newp; // copy data from rhs into this object
i = 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 ret
return ret; // ret and hp are destroyed
} void fun8()
{
HasPtr hp, hp2;
hp=hp2; //这个是拷贝,因为hp2是左值
hp=std::move(hp2); //这个就是move赋值运算了
//自己主动识别!!!
} /**************************************
Advice: Updating the Rule of Three
All five copy-control members should be thought of as a unit: Ordinarily, if a
class defines any of these operations, it usually should define them all. As
we’ve seen, some classes must define the copy constructor, copy-assignment
operator, and destructor to work correctly . Such classes
typically have a resource that the copy members must copy. Ordinarily,
copying a resource entails some amount of overhead. Classes that define the
move constructor and move-assignment operator can avoid this overhead in
those 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 well
private:
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 itself
void 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 Message
void 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 Folders
for (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 sets
swap(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 Folders
for (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 m
void 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 Folders
void 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 Folder
folders.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 msgs
msgs = 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:代码全在,里面各种凝视,我一后还是这样写吧,除了一些特殊的感悟自己写出来,然后大部分大家直接在代码中学习,这样避免了,看那些文字的烦躁,和那些看文字的无聊!!!
今天早上出去溜达一圈,回来早餐吃泡面,尼玛,我真是服了,第一次早上吃泡面,然后把面什么的放碗里,最后把调料又放回了袋子里,我的天!!!

【足迹C++primer】47、Moving Objects(1)的更多相关文章

  1. 【足迹C++primer】47、Moving Objects(2)

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/cutter_point/article/details/37954805 Moving Object ...

  2. 【足迹C++primer】46、动态存储类

    动态存储类 StrVec Class Design StrVec Class Definition class StrVec { public: //构造函数 StrVec():elements(nu ...

  3. 【足迹C++primer】52、,转换和继承虚函数

    转换和继承,虚函数 Understanding conversions between base and derived classes is essential to understanding h ...

  4. 【足迹C++primer】48、函数引用操作符

    函数引用操作符 struct absInt { int operator()(int val) const { cout<<val<<"<->!!!&qu ...

  5. [paper]MaskFusion: Real-Time Recognition, Tracking and Reconstruction of Multiple Moving Objects

    Before 近期在调研关于RGBD在室内移动机器人下的语义导航的研究.目前帝国理工的Andrew Davison在这边有两个团队在研究,分别是Fusion++ 和 这篇 MaskFusion.这篇是 ...

  6. 【足迹C++primer】表达式求值

    表达式求值 /** * 功能:表达式求值(0到9) * 时间:2014年6月15日08:02:31 * 作者:cutter_point */ #include<stdlib.h> #inc ...

  7. 【足迹C++primer】30、概要(泛型算法)

    概要(泛型算法) 大多数算法的头文件中定义algorithm在. 标准库也是第一个文件numeric它定义了一套通用算法. #include<iostream> #include<n ...

  8. 【足迹C++primer】40、动态数组

    动态数组 C++语言定义了第二种new表达式语法.能够分配并初始化一个对象数组.标准库中包括 一个名为allocator的类.同意我们将分配和初始化分离. 12.2.1 new和数组 void fun ...

  9. 【足迹C++primer】49、超载,变化,运营商

    超载,变化,运营商 Conversion Operators 转换操作符 operator type() const Conversions to an array or a function typ ...

随机推荐

  1. 小强的HTML5移动开发之路(50)——jquerymobile页面初始化过程

    为了方便说明和更加直观的展示jquerymobile的页面初始化过程以及各个事件的触发过程,我绘制了一幅流程图: 图中用红色框圈起来的是界面中的事件,測试代码例如以下: <!DOCTYPE ht ...

  2. WPF技术触屏上的应用系列(五): 图片列表异步加载、手指进行缩小、放大、拖动 、惯性滑入滑出等效果

    原文:WPF技术触屏上的应用系列(五): 图片列表异步加载.手指进行缩小.放大.拖动 .惯性滑入滑出等效果 去年某客户单位要做个大屏触屏应用,要对档案资源进行展示之用.客户端是Window7操作系统, ...

  3. C++包括头文件&lt;&gt;和&quot;&quot;差额

    #include "book.h" #include<iostream.h> 在刚開始学习都会有这样的迷惑.有的程序用<>.有的却用"" ...

  4. ASP.NET MVC 5 入门摘要

    翻译和编辑的第一阶段后,.我们已经发出12片ASP.NET MVC 5入门文章. 他们中的大多数来自翻译ASP.NET MVC 5 官方教程,因为本系列文章言简意赅,篇幅适中,从一个web站点演示样例 ...

  5. ./startup.sh: Permission denied

    今天在Linux上部署项目,之前报过这个错误,通过下面方式攻克了.如今发出来备份一下: LINUX权限-bash: ./startup.sh: Permission denied 运行./startu ...

  6. C语言知识汇总

    1. strlen与sizeof差异问题: 以下程序的输出 #include <stdio.h> void main() { char * ptr="hello"; c ...

  7. zoj 1738 - Lagrange&#39;s Four-Square Theorem

    称号:四方形定理.输出可以表示为一个数目不超过四个平方和表示的数. 分析:dp,完全背包.背包分割整数.可用一维分数计算,它也可以被写为一个二维团结. 状态:设f(i,j,k)为前i个数字,取j个数字 ...

  8. String构造函数originalValue.length&gt;size 它发生

    最近观看Jdk6于String源代码被发现String这种施工方法有.源内容如下面: public String(String original) { int size = original.coun ...

  9. 读书时间《JavaScript高级程序设计》三:函数,闭包,作用域

    上一次看了第6章,面向对象.这里接着看第7章. 第7章:函数表达式 定义函数有两种方式:函数声明.函数表达式 //函数声明 function functionName(arg0,arg1,arg2){ ...

  10. DWR入门实例(二)

    DWR(Direct Web Remoting) DWR is a Java library that enables Java on the server and JavaScript in a b ...