C++11函数返回右值引用

我们定义了一个可以传入右值引用的构造函数的类B,在使用std::move的时候,我们非常容易犯一个错误。看下面的代码:

 

class B
{
public:
    B() :s(10), ptr(new int[s])
    {
       std::cout << "default constructor" << std::endl;
       for (int i = 0; i < s; i++)
       {
          ptr[i] = i;
       }
    }
    B(const B& b) :s(b.s)
    {
       std::cout << "B&b" << std::endl;
       for (int i = 0; i < s; i++)
          ptr[i] = b.ptr[i];
    }
    B(B&& b) :s(b.s), ptr(b.ptr)
    {
       std::cout << "B&& b" << std::endl;
       b.ptr = 0;
    }
    ~B()
    {
       std::cout << "~B()" << std::endl;
       if (ptr)
          delete[] ptr;
    }
    friend  std::ostream& operator <<(std::ostream& os, B& b);
private:
    int s;
    int* ptr;
};
std::ostream& operator <<(std::ostream& os,B& b)
{
    os << "[ ";
    for (int i = 0; i < b.s; i++)
       os << b.ptr[i] << " ";
    os << "]" << std::endl;
    return os;
}

B&& f()//注意这里B&&
{
    B tmp;
    return std::move(tmp);
}



B& f2()//注意这里的B&
{
    B t;
    return t;
}
int main()
{
 B b0(f2());
 B b1(f()):
return 0 ;
}

  函数f2返回B的引用,但是B是一个临时对象,马上就会被析构,b0的构造函数传入的参数是一个已经被析构的对象!大家能够非常容易就看出错误所在。

但是,函数f返回std::move(tmp),不容易发现问题。

展开函数f():

首先一个B的临时对象tmp被创建,使用std::move(tmp),将tmp由左值变为右值的引用,它是右值。编译创建一个临时对象B&& _tmp = std::move(tmp)。_tmp被传递给对象b1的构造函数。

无论是右值引用还是左值引用,它们都是引用。所以,f()和f2()发生了同样的错误!

我们可以这样修改:

B f()
{
    B tmp;
    return std::move(tmp);
}

展开函数f():

首先一个B的临时对象tmp被创建,使用std::move(tmp),将tmp由左值变为右值的引用,它是右值。编译创建一个临时对象B _tmp = std::move(tmp)。_tmp调用构造函数B(B&&),转移tmp的空间和大小。_tmp被传递给对象b1的构造函数。

以上。

再附上几个容易混淆的代码:

int& f1(int& a)
{
    return a;
}//正确,返回a的引用

int main()
{
 int&& i = 123;
 int&& a = i;//错误,不能将左值赋给右值引用。如果你犯了这个错误,请务必思考清楚:引用对象在完成初始化后,这个对象的类型是什么。提示,i是一个具名引用。
 int&& b = std::move(i);//正确
 return 0;
}

 


 

重新看了一遍C++11的书,关于引用类型感觉收获了很多。

1.因为我们使用引用类型的变量,就跟使用所引用类型的变量一样,导致我忘了引用类型是一种类型。比如:

int  a = 1;
int& b = a;
int& c = b;
b = c;

自从b被初始化后,用起来它就是一个int的变量一样。实际上,它确实一个int的引用类型,而不是int。

2.关于C++11中模板的参数类型推断,有两个特殊情况。

template<typename T> void function(T&& a);

如果传给function的实参是一个左值,则T被推断为T&,而不是T。这是第一个特殊情况。

如果T& && 被折叠为T&,这是第二个特殊情况。

posted @ 2015-05-02 21:31  P.wang  阅读(17401)  评论(1编辑  收藏  举报