格式工厂 右值引用
Posted 勿在浮沙筑高台
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了格式工厂 右值引用相关的知识,希望对你有一定的参考价值。
版权声明:本文为博主原创文章,未经博主允许不得转载。
由于右值所产生的临时变量问题一直是一种诟病,C++11中引入了右值引用这个核心语言机制,来提升运行期性能.
首先我先说明一下什么是左值和右值: 左值和右值都是针对表达式而言的,左值是指表达式结束后依然存在的持久对象,右值是指表达式结束时就不再存在的临时对象
int b = 20; //这里b是左值 20是右值 ,因为这个表达式过后 20将不存在了 而b依然存在 //同时也可以根据能否取地址来判断是否是左值(能取地址)还是右值(不能取地址),如本例中 20不能取地址顾为右值
右值引用一般都用&&来修饰
下面我们来证实一下上面的右值判断
#include <iostream> #include <vector> using namespace std; void process(int& i)//右值引用 { cout << "process(int&): " << i << endl; } void process(int&& i)//左值引用 { cout << "process(int&&): " << i << endl; } void forward(int&& i)//中间函数 { cout << "forward(int&&): " << i << ", "; process(i); // process(std::forward<int>(i)); } int main(int argc, const char * argv[]) { int a = 0; process(a); process(1); forward(1); //不完美的转交 右值传递后 却调用左值 原因转交过程中转变成一个named obj forward(move(a));//强制转换为右值 也不好用 std::move()强制转换为右值引用 return 0; }
输出结果
是不是发现了调用中间函数的时候丢了什么,把右值引用丢了.使用std::forward<T>()可以避免这种现象(上面的注释部分).
下面我们开始研究一下move()
move(),其实类似于浅拷贝,也可以理解成"偷"
下面我们来实现一个带右值引用的类
这个是不带右值引用的
#include <iostream> #include <vector> using namespace std; class Person { private: int _age; char* _name; size_t _len; void _test_name(const char *s) { _name = new char[_len+1]; memcpy(_name, s, _len); _name[_len] = \'\\0\'; } public: //default ctor Person(): _age(0) , _name(NULL), _len(0){cout<<"default cotr"<< endl;} Person(const int age, const char * p) : _age(age), _len(strlen(p)) { _test_name(p); cout<<"cotr"<<endl; } //dctor ~Person(){ if(_name){ delete _name; } cout<<"default dctor"<<endl; } // copy ctor Person (const Person& p):_age(p._age),_len(p._len){ _test_name(p._name); cout<<"copy ctor"<<endl;} //copy assignment Person & operator=(const Person& p) { if (this != &p){ if(_name) delete _name; _len = p._len; _age = p._age; _test_name(p._name); } else{ cout<< "self Assignment. Nothing to do." <<endl; } cout<<"copy assignment"<<endl; return *this; } };
int main(int argc, const char * argv[]) { Person * obj = new Person(); vector<Person> v1; v1.push_back(*obj); delete obj; return 0; }
输出结果
带右值引用的
#include <iostream> #include <vector> using namespace std; class Person { private: int _age; char* _name; size_t _len; void _test_name(const char *s) { _name = new char[_len+1]; memcpy(_name, s, _len); _name[_len] = \'\\0\'; } public: //default ctor Person(): _age(0) , _name(NULL), _len(0){cout<<"default cotr"<< endl;} Person(const int age, const char * p) : _age(age), _len(strlen(p)) { _test_name(p); cout<<"cotr"<<endl; } //dctor ~Person(){ if(_name){ delete _name; } cout<<"default dctor"<<endl; } // copy ctor Person (const Person& p):_age(p._age),_len(p._len){ _test_name(p._name); cout<<"copy ctor"<<endl;} //copy assignment Person & operator=(const Person& p) { if (this != &p){ if(_name) delete _name; _len = p._len; _age = p._age; _test_name(p._name); } else{ cout<< "self Assignment. Nothing to do." <<endl; } cout<<"copy assignment"<<endl; return *this; } // move cotr , wihth "noexcept" Person(Person&& p) noexcept :_age(p._age) , _name(p._name), _len(p._len){ cout<<"move ctor"<<endl; p._age = 0; p._name = NULL;//必须为NULL 如果你把这里设为空 那么这个函数走完之后将调用析够函数 因为当前的Person类 和你将要析够的Person的_name指向同一部分 析构部分见析构函数 } // move assignment Person& operator=(Person&& p) noexcept { if (this != &p) { if(_name) delete _name; _age = p._age; _len = p._len; _name = p._name; p._age = 0; p._len = 0; p._name = NULL; } cout<<"move assignment"<<endl; return *this; } };
int main(int argc, const char * argv[]) { Person * obj = new Person(); vector<Person> v1; v1.push_back(move(*obj)); delete obj; return 0; }
输出结果
可以见到少调用一次构造函数.以上就是右值引用的简单实现了.
参照<<侯捷 C++新标准 C++11>>
以上是关于格式工厂 右值引用的主要内容,如果未能解决你的问题,请参考以下文章