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的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程