关于lvaue和rvalue, 在c++11以前存在一个有趣的现象:T& 指向lvalue, const T&即可以指向lvalue也可以指向rvalue。
但就是没有一种引用类型,可以限制为只指向rvalue.
这乍起来好像也不是很大问题,但事实上这个缺陷在有些时候严重的限制了我们在某些情况下,写出更有效率的代码。
举个粟子,假设我们有一个类,它包含了一些资源:
复制代码
class holder
{
public:
holder()
{
resource_ = new Resource();
}
~holder()
{
delete resource_;
}
holder(const holder& other)
{
resource_ = new Resource(*other.resource_);
}
holder(holder& other)
{
resource_ = new Resource(*other.resource_);
}
holder& operator=(const holder& other)
{
delete resource_;
resource_ = new Resource(*other.resource_);
return *this;
}
holder& operator=(holder& other)
{
delete resource_;
resource_ = new Resource(*other.resource_);
return *this;
}
private:
Resource* resource_;
};
复制代码
这是个RAII的类,构造函数与析构函数分别负责资源的获取与释放,因此也相应处理了拷贝构造函数(copy constructor)和重载赋值操作符(assignment operator)。
现在假设我们这样来使用这个类。
// 假设存在如一个函数,返回值为holder类型
holder get_holder();
holder h;
h = get_holder();
这小段代码的最后一条语句做了3件事情:
1) 销毁h中的资源。
2) 拷由get_holder()返回的资源。
3) 销毁get_holder()返回的资源。
我们显然可以发现这其中做了些不是很有必要的事情,假如我们可以直接交换h中的资源与get_holder()返回的资源,那这样我们可以直接省掉第二步中的拷贝动作了。
而这里之所以交换能达到相同的效果,是因为get_holder()返回的是临时的变量,是个rvalue,它的生命周期通常来说很短,具体在这里,就是赋值语句完成之后,任何人都没法再引用该rvalue,它马上就要被销毁了。
如果是像下面这样的用法,我们显然不可以直接交换两者的资源:
holder h1;
holder h2;
h1 = h2;
因为h2是个lvalue,它的生命周期较长,在赋值语句结束之后,变量还要存在,还有可能要被别的地方使用。
显然,rvalue的短生命周期给我们提供了在某些情况优化代码的可能。
但这种可能在c++11以前是没法利用到的,因为:我们没法在代码中对rvalue区别对待,在函数体中,无法分辨传进来的参数到底是不是rvalue,缺少一个rvalue的标记。
回忆一下 T& 指向的是lvalue,而const T&指向的,却可能是lvalue或rvalue,没法区分!
为了解决这个问题,c++11中引入了一个新的引用类型:T&&
这种引用指向的变量是个rvalue, 有了这个引用类型,我们前面提到的问题就迎刃而解了。
复制代码
class holder
{
public:
holder()
{
resource_ = new Resource();
}
~holder()
{
if (resource_) delete resource_;
}
holder(const holder& other)
{
resource_ = new Resource(*other.resource_);
}
holder(holder& other)
{
resource_ = new Resource(*other.resource_);
}
holder(holder&& other)
{
resource_ = other.resource_;
other.resource_ = NULL;
}
holder& operator=(const holder& other)
{
delete resource_;
resource_ = new Resource(*other.resource_);
return *this;
}
holder& operator=(holder& other)
{
delete resource_;
resource_ = new Resource(*other.resource_);
return *this;
}
holder& operator=(holder&& other)
{
std::swap(resource_, other.resource_);
return *this;
}
private:
Resource* resource_;
};
复制代码
这时我们再写如下代码的时候:
holder h1;
holder h2;
h1 = h2