右值引用是一种复合类型,跟C++的传统引用很类似。为更准确地区分两种类型,我们把传统的C++引用称为
左值引用
。而使用“引用”这一术语时,我们的意思同时包含两种引用:左值引用和右值引用。
右值引用的行为跟左值引用类似,不同之处在于:右值引用可以绑定到临时量(右值),而(非const的)左值引用却不能绑定到右值。
究竟为何要使用右值引用?
拷贝的开销可以很大。举例来说,对于std::vector,像v2=v1这样的赋值通常包含一次函数调用,一次内存分配和一个循环。当我们确实需要一个vector的两份拷贝时,这当然是可接受的,然而很多情况下我们并不需要:我们常常将一个vector从一个地方复制到另一个地方,接着便覆写了旧的版本
但我们并不想拥有a或b的任何拷贝,而只是想交换他们
move()函数的实现在<type_trait>头文件中
C++11引入了两个新的特殊成员函数:“移动”构造函数和“移动”赋值重载函数。
C::C(C&& other); 这个构造函数不应该申请新的资源,相当于auto_ptr的资源转移
“移动”等号重载函数如下:
C& C::operator=(C&& other);//C++11 move assignment operator.
“移动"赋值重载函数和拷贝构造函数有一点类似,除了在执行赋值前,要把自己的资源释放掉这一
右值引用的行为跟左值引用类似,不同之处在于:右值引用可以绑定到临时量(右值),而(非const的)左值引用却不能绑定到右值。
究竟为何要使用右值引用?
右值引用和左值引用结合起来恰能方便地实现转移语义。右值引用还可以用于实现完美转发,这是C++里面到现在都没有解决的一个问题。从一般程序员的角度来看,使用右值引用,我们得到的将是更加通用,性能也更高的库
template <class T> swap(T& a, T& b)
{
T tmp(a); // now we have two copies of a
a = b; // now we have two copies of b
b = tmp; // now we have two copies of tmp (aka a)
}
拷贝的开销可以很大。举例来说,对于std::vector,像v2=v1这样的赋值通常包含一次函数调用,一次内存分配和一个循环。当我们确实需要一个vector的两份拷贝时,这当然是可接受的,然而很多情况下我们并不需要:我们常常将一个vector从一个地方复制到另一个地方,接着便覆写了旧的版本
但我们并不想拥有a或b的任何拷贝,而只是想交换他们
template <class T> swap(T& a, T& b)
{
T tmp(std::move(a));
a = std::move(b);
b = std::move(tmp);
}
move()函数的实现在<type_trait>头文件中
template <class _Tp>
inline typename remove_reference<_Tp>::type&& move(_Tp&& __t) { typedef typename remove_reference<_Tp>::type _Up; return static_cast<_Up&&>(__t);}
move函数完成的工作实际上微乎其微。它所做的就是接受一个左值或右值参数,然后将它作为右值返回而不引发拷贝构造:C++11引入了两个新的特殊成员函数:“移动”构造函数和“移动”赋值重载函数。
C::C(C&& other); 这个构造函数不应该申请新的资源,相当于auto_ptr的资源转移
“移动”等号重载函数如下:
C& C::operator=(C&& other);//C++11 move assignment operator.
“移动"赋值重载函数和拷贝构造函数有一点类似,除了在执行赋值前,要把自己的资源释放掉这一
#include<iostream>
#include<algorithm>
template<typename T>
class stack
{
T *data;
int size;
int used;
T *Copy(const T *src,size_t srcsize,size_t destsize);
public:
stack(){data =new T[8];size=8;used=0;}
stack(int d);
stack(const stack&);
stack(stack &&);
stack &operator=(const stack &);
stack &operator=(stack &&);
~stack(){if(data!=NULL)delete data;}
void push(T d);
void pop();
T &top();
inline size_t count();
friend ostream &operator<<(ostream &os,stack<T> &s);
};
template<typename T>
stack<T>::stack(int d)
{
data=new T[d];
size=d;
used=0;
}
template<typename T>
stack<T>::stack(const stack<T> &s):data(Copy(s.data,s.size,s.size)),size(s.size),used(s.used)
{
}
template<typename T>
T *stack<T>::Copy(const T *src,size_t srcsize,size_t destsize)
{
//assert(destsize>=srcsize);
T *dest=new T[destsize];
try
{
copy(src,src+srcsize,dest);
}
catch(...)
{
delete []dest;
throw;
}
return dest;
}
template<typename T>
stack<T>::stack(stack<T> &&s):data(s.data),size(s.size),used(s.used)
{
cout<<"cop stack<T> &&s ";
s.data=nullptr;
s.size=0;
s.used=0;
}
template<typename T>
stack<T> &stack<T>::operator=(const stack<T> &s)
{
if(*this!=s)
{
if(data!=NULL)
delete data;
data=Copy(s.data,s.size,s.size);
size=s.size;
used=s.used;
}
return *this;
}
template<typename T>
stack<T> &stack<T>::operator=(stack<T> &&s)
{
cout<<"stack<T> &&s";
if(*this!=s)
{
data=s.data;
size=s.size;
used=s.used;
s.data=nullptr;
s.size=0;
s.used=0;
}
return *this;
}
template<typename T>
void stack<T>::push(T d)
{
if(used==size)
{
size_t nsize=2*size;
T *dest=Copy(data,size,nsize);
delete data;
data=dest;
size=nsize;
}
data[used++]=d;
}
template<typename T>
void stack<T>::pop()
{
if(used==0)
throw "pop error";
else
--used;
}
template<typename T>
T &stack<T>::top()
{
if(used==0)
throw "top error";
else
return data[used-1];
}
template<typename T>
size_t stack<T>::count()
{
return used;
}
template<typename T>
ostream &operator<<(ostream &os,stack<T> &p)
{
for(int i=p.used;i>=0;--i)
os<<p.top();
return os;
}
int main()
{
stack<int> s;
for(int i=10;i>=0;--i)
s.push(i);
//cout<<s;
stack<int> s1(static_cast<stack<int>&&>(s));
stack<int> s2=static_cast<stack<int>&&>(s1);
//stack<int> &&s3=s;
cout<<"s\n";
for(int i=s.count();i>0;--i)
{
cout<<s.top();
s.pop();
}
cout<<"s1\n";
for(int i=s1.count();i>0;--i)
{
cout<<s1.top();
s1.pop();
}
cout<<"s2\n";
for(int i=s2.count();i>0;--i)
{
cout<<s2.top();
s2.pop();
}
}