右值引用(Rvalue)
可以大幅改善容器的性能
当对象内部含有指针时,可以使用右值来窃取对象
原理
当右边的对象是一个右值时,左侧的对象可以偷取右侧对象的资源
1 2 3 4
| int x=foo() int* p=&foo() foo()=7;
|
右值引用(Rvalue)
可以大幅改善容器的性能
原理
当右边的对象是一个右值时,左侧的对象可以偷取右侧对象的资源
1 2 3 4
| int x=foo() int* p=&foo() foo()=7;
|
cpp 11后我们认为右值的对象时可以被窃取资源的
为此我们需要:
- 必须有语法让我们在调用端诉编译器,这是个Rvalue
- 必须有语法放我们在被调用段写出一个专门处理Rvalue的所谓move assignment函数
code
1 2 3 4 5 6 7 8 9 10 11 12 13
| class MyString{ private: char* _data; public: MyString(const Mystring& str):initialization list{
} Mystring(MyString&& str)noexcept:initialization list{ ... } }
|
G2.9
1 2 3 4 5 6 7 8 9 10 11
| iterator insert(iterator posistion,const T&x){ size_type n=posistion-begin(); if(finish !=end_of_storge && position ==end()){ construct(finish,x); ++finish; }else{ insert_aux(position,x); } return begin()+n; }
|
G4.9
1 2 3 4 5 6 7
| iterator insert(const_iterator __position,const value_type& __x);
iterator instert(const_iterator __position,value_type&& __x){ return emplace(__position,std::move(__x)) }
|
旧版问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| void process(int& i){ cout<<"process(int &i):"<<i<<endl; }
void process(int&& i){ cout<<"process(int&&):"<<i<<endl; }
void forward(int&& i){ out<<"forward(int&&):"<<i<<endl; process(i); } int a=0; forward(2); forward(move(a));
|
改进版本
标准库提供的完美的传递过去
1 2 3 4 5 6
| template <typename T1,typename T2> void functionA(T1&& t1,T2&& t2){ funtionB(std::forward<T1>(t1), std::forward<T2>(t2)) }
|
使用时要实现一下功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| private: char* _data; public:
MyString(const Mystring& str):initialization list{
}
Mystring(MyString&& str)noexcept:initialization list{ ... }
MyString& operator=(const MyString& str){
return *this; }
Mystring& operator=(MyString&& str){ noexcpt{ return *this; } }
|
例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| class MyString{ public: static size_t DCtor; static size_t Ctor; static size_t CCtor; static size_t CAsgn; static size_t MCtor; static size_t MAsgn; static size_t Dtor; private: char* _data; size_t _len; void _init_data(const char*s){ _data = new char[_len+1]; memcpy(_data,s,_len); _data[_len]='\0'; } public: MyString():_data(NULL),_len(0){++DCtor;} MyString(const char* p):_len(strlen(p)){ ++Ctor; _init_data(p); }
MyString(const Mystring& str):_len(str._len){ ++CCtor; _init_data(str._data); } MyString(Mystring& str)noexcept:_data(str._data),_len(str._len){ ++MCtor; str._len=0; str._data=NULL; }
MyString& operator=(const MyString& str){ ++CAsgn; if(this != &str){ if(_data) delete _data; _len=str._len; _init_data(str._data); }else{
} return *this; }
MyString& operator=(MyString&& str) noexcept{ if(this !=& str){ if(_data) delete _data; _len = str._len; _data=str._data; str._len=0; str._data=NULL } } virtual ~MyString(){ ++Dtor; if(_data){ delete _data; } }
bool operator<(const MyString& rhs)const { return string(this._data)<string(rhs._data); }
bool operator=(const MyString& rhs)const{ return string(this._data)=string(rhs._data); }
char* get()const{return _data;} };
|
对于性能的影响
- vector
- 插入元素,影响巨大,是否实现移动构造
- 容器拷贝,影响巨大,需要使用std::move()
- 容器交换,影响巨大,需要使用std::move()
- deque
- 插入元素,影响不大 (不一定,和元素的位置相关)
- 容器拷贝,影响巨大,需要使用std::move()
- 容器交换,影响巨大,需要使用std::move()
- list 链表
- 插入元素,影响不大
- 容器拷贝,影响巨大,需要使用std::move()
- 容器交换,影响巨大,需要使用std::move()
- multiset(红黑树)
- 插入元素,影响不大
- 容器拷贝,影响巨大,需要使用std::move()
- 容器交换,影响巨大,需要使用std::move()
- unordered_multiset(hash_table)
- 插入元素, 差别不大
- 容器拷贝,影响巨大,需要使用std::move()
- 容器交换,影响巨大,需要使用std::move()
原理
- 容器拷贝
- 如果使用拷贝构造,会进行内存的分配,并且拷贝每一个内容
- 如果使用移动构造,只更改对应的容器的指针。//常量的时间