学习C++11之引用

1、左值引用

左值引用只能绑定左值,不能绑定右值.

如下:

int x = 1;
int &y = x;                //绑定左值,正确
int &z = 2;                //绑定右值2,编译错误
但是可以将 右值绑定到一个const左值引用(这是一个例外)

如:

 //右值绑定到const左值引用
int const &i = 28;                 //正确
在右值引用诞生之前,为了传递临时对象到函数中以引用,这将允许实参隐式转换到形参类型,如下:

void print(std::string cosnt& s) {}
print("hello");        //“hello”字符串是临时字符串对象,也是右值


2、右值引用

右值引用只能绑定右值,不能绑定左值.使用两个&&表示右值引用.

如:

int&& i = 8;            
int j = 18;       
int&& k = j;               //编译错误
通过使用函数重载来决定函数参数是左值/右值,重载函数参数设置为左值引用和右值引用.

void fun_reference(int& a)
{
     std::cout << "左值引用:" << a << std::endl;
}

void fun_reference(int&& a)
{
     std::cout << "右值引用:" << a << std::endl;
}

int main()
{
    int x = 8;
    fun_reference(x);     //输出左值引用:8
    fun_reference(18);  //输出右值引用:18
    return 0;
}

3、move语义

(1)move的作用是避免复制,提高效率.考虑一个函数以std::vector<int>作为参数,函数作用是在不改变实参的情况下,在vector中添加元素,旧方法使用常量左值引用作为参数,在内部先拷贝,再添加。如下所示:

void process_copy(std::vector<int> const& vec_)
{
     std::vector<int> vec(vec_);
     vec.push_back(42);
}
上面函数能够传递左值和右值,但在内部都强制拷贝。假如使用右值引用重载上面函数,可以避免传递右值时强制使用拷贝。如下:

void process_copy(std::vector<int> && vec)
{
       vec.push_back(42);
}

(2)move构造函数

class X
{
private:
       int* data;
public:
       X():
         data(new int[1000000])
         {}
       ~X()
       {
          delete [] data;
       }
       X(const X& other):
          data(new int[1000000])
       {
           std::copy(other.data,other.data+1000              000,data);
       }
       X(X&& other):
            data(other.data)
       {
           other.data=nullptr;
       }
};
move构造函数允许拥有者的指针在对象之间传递,允许unique_ptr<>(拥有move构造函数)作为一个函数的返回值,函数返回值属于临时对象,可以作为右值传递给右值引用,避免了拷贝。

(3)std::move()

对于有名字的对象,可以使用std::move()函数和static_cast<>强制转换为右值,在赋值时,将调用效率更高的move赋值运算符,避免了拷贝

X x1;
X x2=std::move(x1);  //调用move赋值运算符
X x3=static_cast<X&&>(x2); //同上

(4)注意,尽管右值引用能够绑定右值,但在函数体中,右值引用将会被函数”定义“为左值。如下:

void do_stuff(X&& x_)
{
    X a(x_);               //调用拷贝构造函数
    X b(std::move(x_));      
}
do_stuff(X());             //传递右值,但在函数体中第一行代码将会调用拷贝构造函数
X x;
do_stuff(x);              //这个调用就错误,左值不能被右值引用绑定

(5)右值引用和函数模板

当右值引用作为函数模板参数,会有差异。如果函数参数是一个模板参数的右值引用,模板推演参数类型将分两种:

template<typename T>
void foo(T&& t)
{}

1)若是使用左值作为参数调用,模板将参数类型推演为左值引用。

int i=42;
foo(i);           //函数将被推演为:foo<int&>(i)
2)若是使用右值作为参数调用,模板将参数类型推演为值的类型

foo(42);         //推演为foo<int>(42)
foo(3.14159);    //推演为foo<float>(3.14159)
foo(std::string()); //推演为foo<std::string>(std::string())



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值