C++ move和forward
2021/11/21 17:10:20
本文主要是介绍C++ move和forward,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
在这两篇文件的基础之上;
CSDN
CSDN
vector右值引用的push_back方法
修改之前vector代码中的push_back
// /*void push_back(const T &val)//接收左值 { if (full()) expand(); _allocator.construct(_last, val); _last++; } void push_back(T &&val)//接收右值 一个右值引用变量本身还是一个左值 { if (full()) expand(); _allocator.construct(_last, std::move(val)); //val本身还是左值啊。匹配的还是左值的construct。怎么办? //使用std::move把val 强转成右值引用类型 _last++; }*/ template<typename Ty>//函数模板的类型推演 + 引用折叠 void push_back(Ty &&val)// { if (full()) expand(); //move(左值):移动语义,得到右值类型 (int&&)a //forward:类型完美转发,能够识别左值和右值类型 _allocator.construct(_last, std::forward<Ty>(val)); _last++; }
使用void push_back(Ty &&val)为什么可以识别左值和右值呢?
引用重叠:
左值引用+右值引用=左值引用
右值引用+右值引用=右值引用
例如:
push_back(左值引用); 由于接收是Ty &&val;右值引用;左值引用+右值引用=左值引用 最终依然是一个左值引用;
同理右值引用;
通过std::forword可以识别左值和右值
/*void construct(T *p, const T &val)//负责对象构造 { new (p) T(val); // 定位new } void construct(T *p, T &&val)//负责责对象构造 { new (p) T(std::move(val)); //定位new 强转成右值引用类型 调用底层的T右值引用的拷贝构造函数 }*/ //可以用std::move强转成右值,也可以如下做法: //无法区分右值和左值的简便的解决办法: template<typename Ty> void construct(T *p, Ty &&val) { new (p) T(std::forward<Ty>(val)); }
最终代码:
#include <iostream> //容器的空间配置器 template <typename T> struct Allocator { T* allocate(size_t size)//只负责内存开辟 { return (T*)malloc(sizeof(T) * size); } void deallocate(void *p)//只负责内存释放 { free(p); } template<typename Ty> void construct(T *p, Ty &&val) { new (p) T(std::forward<Ty>(val)); } void destroy(T *p)//只负责对象析构 { p->~T();//~T()代表了T类型的析构函数 } }; template <typename T, typename Alloc = Allocator<T>> class vector//向量容器 { public: vector(int size = 10)//构造 { //_first = new T[size]; _first = _allocator.allocate(size); _last = _first; _end = _first + size; } ~vector()//析构 { //delete[]_first; for (T *p = _first; p != _last; ++p) { _allocator.destroy(p);//把_first指针指向的数组的有效元素析构 } _allocator.deallocate(_first);//释放堆上的数组内存 _first = _last = _end = nullptr; } vector(const vector<T> &rhs)//拷贝构造 { int size = rhs._end - rhs._first;//空间大小 //_first = new T[size]; _first = _allocator.allocate(size); int len = rhs._last - rhs._first;//有效元素 for (int i = 0; i < len; ++i) { //_first[i] = rhs._first[i]; _allocator.construct(_first + i, rhs._first[i]); } _last = _first + len; _end = _first + size; } vector<T>& operator=(const vector<T> &rhs)//赋值运算符重载 { if (this == &rhs) { return *this; } //delete[]_first; for (T *p = _first; p != _last; ++p) { _allocator.destory(p);//把_first指针指向的数组的有效元素析构 } _allocator.deallocate(_first);//释放堆上的数组内存 int size = rhs._end - rhs._first;//空间大小 _first = _allocator.allocate(size); int len = rhs._last - rhs._first;//有效元素 for (int i = 0; i < len; ++i) { _allocator.construct(_first + i, rhs._first[i]); } _last = _first + len; _end = _first + size; return *this; } template<typename Ty>//函数模板的类型推演 + 引用折叠 void push_back(Ty &&val)//Ty CMyString& + && = CMyString& { if (full()) expand(); //move(左值):移动语义,得到右值类型 (int&&)a //forward:类型完美转发,能够识别左值和右值类型 _allocator.construct(_last, std::forward<Ty>(val)); _last++; } void pop_back()//尾删 { if (empty()) return; verify(_last - 1, _last); //erase(it); verift(it._ptr, _last); //insert(it,val); verift(it._ptr, _last); //--_last; //不仅要把_last指针--,还需要析构删除的元素 --_last; _allocator.destroy(_last); } T back()const//返回容器末尾元素值 { return *(_last - 1); } bool full()const { return _last == _end; } bool empty()const { return _first == _last; } int size()const//返回容器中元素个数 { return _last - _first; } T& operator[](int index) { if (index < 0 || index >= size()) { throw "OutOfRangeException"; } return _first[index]; } //迭代器一般实现成容器的嵌套类型 class iterator { public: friend class vector <T, Alloc>; //新生成当前容器某一个位置元素的迭代器 iterator(vector<T, Alloc> *pvec = nullptr , T *ptr = nullptr) :_ptr(ptr), _pVec(pvec) { Iterator_Base *itb = new Iterator_Base(this, _pVec->_head._next); _pVec->_head._next = itb; } bool operator!=(const iterator &it)const { //检查迭代器的有效性 if (_pVec == nullptr || _pVec != it._pVec)//迭代器为空或迭代两个不同容器 { throw "iterator incompatable!"; } return _ptr != it._ptr; } void operator++() { //检查迭代器有效性 if (_pVec == nullptr) { throw "iterator incalid!"; } _ptr++; } T& operator*() { //检查迭代器有效性 if (_pVec == nullptr) { throw "iterator invalid!"; } return *_ptr; } const T& operator*()const { if (_pVec == nullptr) { throw "iterator invalid!"; } return *_ptr; } private: T *_ptr; //当前迭代器是哪个容器对象 vector<T, Alloc> *_pVec;//指向当前对象容器的指针 }; iterator begin() { return iterator(this, _first); } iterator end() { return iterator(this, _last); } //检查迭代器失效 void verify(T *first, T *last) { Iterator_Base *pre = &this->_head; Iterator_Base *it = this->_head._next; while (it != nullptr) { if (it->_cur->_ptr > first && it->_cur->_ptr <= last) { //迭代器失效,把iterator持有的容器指针置nullptr it->_cur->_pVec = nullptr; //删除当前迭代器节点,继续判断后面的迭代器节点是否失效 pre->_next = it->_next; delete it; it = pre->_next; } else { pre = it; it = it->_next; } } } //自定义vector容器insert方法实现 iterator insert(iterator it, const T &val) { //1.这里我们未考虑扩容 //2.还未考虑it._ptr指针合法性,假设它合法 verify(it._ptr - 1, _last); T *p = _last; while (p > it._ptr) { _allocator.construct(p, *(p - 1)); _allocator.destroy(p - 1); p--; } _allocator.construct(p, val); _last++; return iterator(this, p); } //自定义vector容器erase方法实现 iterator erase(iterator it) { verify(it._ptr - 1, _last); T *p = it._ptr; while (p < _last - 1) { _allocator.destroy(p); _allocator.construct(p, *(p + 1)); p++; } _allocator.destroy(p); _last--; return iterator(this, it._ptr); } private: T *_first;//起始数组位置 T *_last;//指向最后一个有效元素后继位置 T *_end;//指向数组空间的后继位置 Alloc _allocator;//定义容器的空间配置器对象 //容器迭代器失效增加代码 struct Iterator_Base { Iterator_Base(iterator *c = nullptr, Iterator_Base *n = nullptr) :_cur(c), _next(n) {} iterator *_cur; Iterator_Base *_next; }; Iterator_Base _head; void expand()//扩容 { int size = _end - _first; //T *ptmp = new T[2*size]; T *ptmp = _allocator.allocate(2 * size); for (int i = 0; i < size; ++i) { _allocator.construct(ptmp + i, _first[i]); //ptmp[i] = _first[i]; } //delete[]_first; for (T *p = _first; p != _last; ++p) { _allocator.destroy(p); } _allocator.deallocate(_first); _first = ptmp; _last = _first + size; _end = _first + 2 * size; } }; #include <iostream> using namespace std; class Test { public: Test(int a = 10) :ma(a) { cout << "Test(int)" << endl; } ~Test() { cout << "~Test()" << endl; } Test(const Test &t) :ma(t.ma) { cout << "Test(const Test&)" << endl; } Test(Test &&t) :ma(t.ma) { cout << "Test(const Test&&)" << endl; } Test& operator=(const Test &t) { cout << "operator=(const Test &t)" << endl; ma = t.ma; return *this; } Test& operator=(Test &&t) { cout << "operator=((Test &&t)" << endl; ma = t.ma; return *this; } private: int ma; }; int main() { Test t1; std::cout << "---------------begin\n"; vector<Test> v; v.push_back(t1); v.push_back(Test(123)); std::cout << "---------------end\n"; return 0; }
move和forword的实现
std::move的底层实现
// FUNCTION TEMPLATE move template<class _Ty> _NODISCARD constexpr remove_reference_t<_Ty>&& move(_Ty&& _Arg) noexcept { // forward _Arg as movable return (static_cast<remove_reference_t<_Ty>&&>(_Arg)); }
static_cast显示将一个左值转换为一个右值引用
std::forward的底层实现
// FUNCTION TEMPLATE forward template<class _Ty> _NODISCARD constexpr _Ty&& forward(remove_reference_t<_Ty>& _Arg) noexcept { // forward an lvalue as either an lvalue or an rvalue return (static_cast<_Ty&&>(_Arg)); } template<class _Ty> _NODISCARD constexpr _Ty&& forward(remove_reference_t<_Ty>&& _Arg) noexcept { // forward an rvalue as an rvalue static_assert(!is_lvalue_reference_v<_Ty>, "bad forward call"); return (static_cast<_Ty&&>(_Arg)); }
对左值引用和右值引用分别使用不同的模板函数,都返回了 static_cast<_Ty&&>(_Arg)
这篇关于C++ move和forward的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-22怎么通过控制台去看我的页面渲染的内容在哪个文件中呢-icode9专业技术文章分享
- 2024-12-22el-tabs 组件只被引用了一次,但有时会渲染两次是什么原因?-icode9专业技术文章分享
- 2024-12-22wordpress有哪些好的安全插件?-icode9专业技术文章分享
- 2024-12-22wordpress如何查看系统有哪些cron任务?-icode9专业技术文章分享
- 2024-12-21Svg Sprite Icon教程:轻松入门与应用指南
- 2024-12-20Excel数据导出实战:新手必学的简单教程
- 2024-12-20RBAC的权限实战:新手入门教程
- 2024-12-20Svg Sprite Icon实战:从入门到上手的全面指南
- 2024-12-20LCD1602显示模块详解
- 2024-12-20利用Gemini构建处理各种PDF文档的Document AI管道