【足迹C++primer】47、Moving Objects(1)
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;
}
【足迹C++primer】47、Moving Objects(1)的更多相关文章
- 【足迹C++primer】47、Moving Objects(2)
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/cutter_point/article/details/37954805 Moving Object ...
- 【足迹C++primer】46、动态存储类
动态存储类 StrVec Class Design StrVec Class Definition class StrVec { public: //构造函数 StrVec():elements(nu ...
- 【足迹C++primer】52、,转换和继承虚函数
转换和继承,虚函数 Understanding conversions between base and derived classes is essential to understanding h ...
- 【足迹C++primer】48、函数引用操作符
函数引用操作符 struct absInt { int operator()(int val) const { cout<<val<<"<->!!!&qu ...
- [paper]MaskFusion: Real-Time Recognition, Tracking and Reconstruction of Multiple Moving Objects
Before 近期在调研关于RGBD在室内移动机器人下的语义导航的研究.目前帝国理工的Andrew Davison在这边有两个团队在研究,分别是Fusion++ 和 这篇 MaskFusion.这篇是 ...
- 【足迹C++primer】表达式求值
表达式求值 /** * 功能:表达式求值(0到9) * 时间:2014年6月15日08:02:31 * 作者:cutter_point */ #include<stdlib.h> #inc ...
- 【足迹C++primer】30、概要(泛型算法)
概要(泛型算法) 大多数算法的头文件中定义algorithm在. 标准库也是第一个文件numeric它定义了一套通用算法. #include<iostream> #include<n ...
- 【足迹C++primer】40、动态数组
动态数组 C++语言定义了第二种new表达式语法.能够分配并初始化一个对象数组.标准库中包括 一个名为allocator的类.同意我们将分配和初始化分离. 12.2.1 new和数组 void fun ...
- 【足迹C++primer】49、超载,变化,运营商
超载,变化,运营商 Conversion Operators 转换操作符 operator type() const Conversions to an array or a function typ ...
随机推荐
- cocos2dx 遮罩层 android 手机上 失败
1.CCClippingNode使用(在模拟器上ok,在手机上不行),实现多个剪切区域 local layer=CCLayerColor:create(ccc4(0,0,0,110)) --/ ...
- MFC 将文件拖进对话框获得文件信息
非常多软件都支持直接将文件拖进去进行处理的功能,详细一点如暴风影音,将视频或者音频文件拖进去就会自己主动開始播放,那么这个功能在MFC上面怎么实现的呢?事实上非常easy,过程例如以下: 第一步:将对 ...
- 编译hibernate源代码
1)安装gradle,gradle是一个类似maven的构建工具 2)安装gitclient. 从网址 https://github.com/hibernate/hibernate-orm 上clon ...
- 双链表---LinkedList的重写
重写Linkedlist类,改写为MyLinkedList,未继承Iterable类. public class MyLinkedList<AnyType> { private int t ...
- 黑马day11 脏读数据&解
数据库: create table account ( id int primary key auto_increment, name varchar(20), money double ); ins ...
- uitextField单词的方法和抖动的限制
这种方法还可以找到在线. 如下面的详细信息: .h文件 #import <UIKit/UIKit.h> @interface UITextField (LimitLength) /** * ...
- tomcatport占用,如何识别和kill
开始-执行-cmd,进netstat -ano你可以看到整个port入住. 增加要想知道谁占用了我们的port8080,输入下面命令 C:\Documents and Settings\Adminis ...
- web 环境项目(intellj部署的tomcat) 重启时报 Exception in thread "HouseKeeper" java.lang.NullPointerException (转)
Exception in thread "HouseKeeper" java.lang.NullPointerException at org.logicalcobwebs.pro ...
- Android图表日历控件组件
1.图表引擎 - AChartEngine AChartEngine是一款基于Android的图表绘制引擎,它为Android开发人员提供了非常多有用的图表绘制工具类,假设你须要在Android应用中 ...
- Log4j配置文件位置+Spring数据源配置文件位置
一个.Log4j配置文件位置 1.加载自己主动 当应用程序启动,缺省情况下,这将是src文件夹搜索log4j.xml型材.如果不存在.我们将继续寻找log4j.properties文件,仅仅要找到当中 ...