ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

C++ move和forward

2021-11-21 16:02:18  阅读:159  来源: 互联网

标签:last val move C++ ._ forward size allocator first


在这两篇文件的基础之上;

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)

标签:last,val,move,C++,._,forward,size,allocator,first
来源: https://blog.csdn.net/LIJIWEI0611/article/details/121451239

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有