一,ref的含义
ref(obj)返回值可以简单理解为一个ref类对象,在此对象中有一个变量指针指向obj的地址,也就是说ref类中的数据包含了obj的引用。当然,实际实现和这个描述有一定区别,但你可以简单这样理解。
二,为什么要引入ref
看一下这段代码:
#include <iostream>
#include <thread>
#include <functional>
using namespace std;
void thread_fun(int& n)
{
n++;
}
int main()
{
int num = 0;
//需要在thread中修改num的值,需要把num的引用作为参数传递给thread
thread t1(thread_fun, num);
t1.join();
cout << "num = " << num << endl;
}
在这段代码中,我们要实现一个线程thead_fun,并且在线程中改变num的值。但代码是编译失败的。我们看一下thread的定义,找到如下构造函数:
_NODISCARD_CTOR_THREAD explicit thread(_Fn&& _Fx, _Args&&... _Ax) {
_Start(_STD forward<_Fn>(_Fx), _STD forward<_Args>(_Ax)...);
}
看一下_Args&&, 这个是右值引用,所以thread t1(thread_fun, num);语句中的num会转成右值引用。但函数中void thread_fun(int& n)的参数为左值引用,正是这个原因导致编译失败。
如果想编译通过,需要把代码中的thread t1(thread_fun, num); 改为thread t1(thread_fun, ref(num));
三,什么时候需要使用ref
看代码:
#include <iostream>
#include <thread>
#include <tuple>
#include <functional>
using namespace std;
void thread_fun(int& n)
{
n++;
}
void func(int& n)
{
n++;
}
int main()
{
int num = 0;
//需要在thread中修改num的值,需要把num的引用作为参数传递给thread
thread t1(thread_fun, ref(num));
t1.join();
cout << "num = " << num << endl;
//绑定函数中,需要传递参数引用给函数。
function<void()> f = bind(func, ref(num));
f();
cout << "num = " << num << endl;
//tuple中需要使用引用
int a = 1;
int b = 2;
int c = 3;
tuple<int&,int,int> t = make_tuple(ref(a), b, c);
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
get<0>(t) = 4;
cout << "a = " << a << endl;
}
bind函数原型如下:
_NODISCARD _CONSTEXPR20 _Binder<_Unforced, _Fx, _Types...> bind(_Fx&& _Func, _Types&&... _Args) {
return _Binder<_Unforced, _Fx, _Types...>(_STD forward<_Fx>(_Func), _STD forward<_Types>(_Args)...);
}
看_Types&&... _Args这个也是右值引用。
make_tuple原型如下:
_NODISCARD constexpr tuple<_Unrefwrap_t<_Types>...> make_tuple(_Types&&... _Args) { // make tuple from elements
using _Ttype = tuple<_Unrefwrap_t<_Types>...>;
return _Ttype(_STD forward<_Types>(_Args)...);
}
参数_Types&&... _Args也是右值引用。
总结:如果参数是右值引用的情况下要传递引用,则需使用ref