C中ref用法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C中ref用法相关的知识,希望对你有一定的参考价值。


i = 44;

static void Main()

int val = 0;
Method(ref val);
// val is now 44

这样一段代码val =44,

有没有什么办法void Main()在调用Method(ref val)时 ,先给Method(ref val) 传入一个参数,然后再把Method(ref val) 返回给void Main()
static void Method(ref int i)

i = 44;

static void Main()

int val = 0;
Method(ref val);
// val is now 44


我这是静态也面 标签替换

  C#中ref 关键字使参数按引用传递。 其效果是,当控制权传递回调用方法时,在方法中对参数的任何更改都将反映在该变量中。

  注意:不要将“通过引用传递”概念与“引用类型”概念相混淆。 这两个概念不相关;方法参数无论是值类型还是引用类型,都可通过 ref 进行修饰。 因此,通过引用传递值类型时没有值类型装箱。

  若要使用 ref 参数,则方法定义和调用方法都必须显式使用 ref 关键字。例如:

 class RefExample
    
        staticvoid Method(refint i)
        
            i = 44;
        
        staticvoid Main()
        
            int val = 0;
            Method(ref val);
            // val is now 44
        
    
参考技术A static void Method(ref int i,int value)

i = value;
本回答被提问者采纳
参考技术B fewfefewf 参考技术C 你的意思是,把这个方法当作返回值,用于此处调用么??可以倒是可以,定义一个委托,把这个方法注册进去就行了...但是我不知道你搞这么复杂有什么意义

不好意思,我实在看不出来你用这么两个方法到底实现哪门子的标签替换...而且我上下看了5遍了,都不知道你说的到底是神马意思,恕我才疏学浅吧....

std::ref用法以及和&引用区别

1、std::ref是什么?

  • 关于c++中的std::ref,std::ref在c++11引入。本文通过讲解std::ref的常用方式,及剖析下std::ref内部实现,然后我们再进一步分析为什么使用std::ref。

  • ref是个函数模板:

    • 用来构建一个reference_wrapper对象并返回,该对象拥有传入的elem变量的引用。如果参数本身是一个reference_wrapper类型的对象,则创建该对象的一个副本,并返回。

2、为什么要有std::ref

  • std::ref主要在函数式编程(如std::bind)时使用,bind是对参数直接拷贝,无法传入引用(即使你传入的实参是引用类型也不行),故引入std::ref()。使用std::ref可以在模板传参的时候传入引用。

  • std::ref能使用reference_wrapper包装好的引用对象代替原本会被识别的值类型,而reference_wrapper能隐式转换为被引用的值的引用类型。

代码如下:

#include <iostream>
#include <functional>
#include<vector>

using namespace std;

//std::ref主要是考虑函数式编程(如std::bind)在使用时,是对参数直接拷贝,而不是引用
void f(int& a, int& b, int& c)

    cout << "in function a = " << a << "  b = " << b << "  c = " << c << endl;
    cout << "in function a = " << &a << "  b = " << &b << "  c = " << &c << endl;
    a += 1;
    b += 10;
    c += 100;


int main() 

    int n1 = 1, n2 = 10, n3 = 100;
    int& r1 = n1;
    int& r2 = n2;

    function<void()> f1 = bind(f, r1, r2, ref(n3));		
    //前两个参数即便是引用类型,bind 传入的还是其值的拷贝,第三个参数传入 reference_wrapper 对象,该对象可隐式的转换为值的引用

    f1();
    cout << "out function a = " << n1 << "  b = " << n2 << "  c = " << n3 << endl;
    cout << "out function a = " << &n1 << "  b = " << &n2 << "  c = " << &n3 << endl;
    f1();
    cout << "out function a = " << n1 << "  b = " << n2 << "  c = " << n3 << endl;
    cout << "out function a = " << &n1 << "  b = " << &n2 << "  c = " << &n3 << endl;
    return 0;


输出结果:

in function a = 1  b = 10  c = 100
in function a = 0000006B90EFF710  b = 0000006B90EFF708  c = 0000006B90EFF684
out function a = 1  b = 10  c = 200
out function a = 0000006B90EFF644  b = 0000006B90EFF664  c = 0000006B90EFF684
in function a = 2  b = 20  c = 200
in function a = 0000006B90EFF710  b = 0000006B90EFF708  c = 0000006B90EFF684
out function a = 1  b = 10  c = 300
out function a = 0000006B90EFF644  b = 0000006B90EFF664  c = 0000006B90EFF684

3、std::ref和引用的区别

  • 首先就是,上面的例子里,使用bind的时候,普通引用和std::ref引用有区别。

  • std::ref只是尝试模拟引用传递,并不能真正变成引用,在非模板情况下,std::ref根本没法实现引用传递,只有模板自动推导类型或类型隐式转换时,std::ref能用包装类型reference_wrapper来代替原本会被识别的值类型,而reference_wrapper能隐式转换为被引用的值的引用类型。

  • 目前我只遇到过类型转换时,ref和普通引用的区别,模板自动推导类型的情况还没遇到过。

4、std::ref 用法

int n1 = 0;
auto n2 = std::ref(n1);

n2++;
n1++;

std::cout << n1 << std::endl;  // 2
std::cout << n2 << std::endl;  // 2

  • 可以看到 是把n1的引用传递给了n2,分别进行加法,可以看到n2是n1的引用,最终得到的值都是2。

  • 那么大家可能会想,我都已经有了’int& a = b’的这种引用赋值的语法了,为什么c++11又出现了一个std::ref,我们继续来看例子:

    #include <iostream>
    #include <thread>
    
    void thread_func(int& n2)  // error, >> int n2
        n2++;
    
    
    int main() 
        int n1 = 0;
        std::thread t1(thread_func, n1);
    
        t1.join();
        std::cout << n1 << std::endl;
    
    
    
    • 我们如果写成这样是编译不过的,除非是去掉引用符号,那么我如果非要传引用怎么办呢?

      // snap ...
      
      int main() 
          int n1 = 0;
          std::thread t1(thread_func, std::ref(n1));
      
          t1.join();
          std::cout << n1 << std::endl; // 1
      
      
  • 这样可以看到引用传递成功,并且能够达到我们效果,我们再来看个例子:

#include <iostream>
#include <functional>

void func(int& n2) 
    n2++;


int main() 
    int n1 = 0;
    auto bind_fn = std::bind(&func, std::ref(n1));

    bind_fn();
    std::cout << n1 << std::endl; // 1


  • 这里我们也发现std::bind这样也是需要通过std::ref来实现bind引用。

    • 那么我们其实可以看的出来,std::bind或者std::thread里是做了什么导致我们原来的通过&传递引用的方式失效,或者说std::ref是做了什么才能使得我们使用std::bind和std::thread能够传递引用。

    • 那么我们展开std::ref看看他的真面目,大致内容如下:

template <class _Ty>
reference_wrapper<_Ty> ref(_Ty& _Val) noexcept 
    return reference_wrapper<_Ty>(_Val);


  • 这里我们看到std::ref最终只是被包装成reference_wrapper返回,所以关键点还是std::reference_wrapper。

5、 为什么使用std::ref

  • 我们看下为什么std::bind或者std::thread为什么要使用reference_wrapper,我们以std::bind为例子吧,我们大致去跟踪下std::bind,跟踪的目的是看传递bound参数(即我们传给bind函数的参数)的生命周期,以vs2019的实现为例:
template <class _Fx, class... _Types>
_NODISCARD _CONSTEXPR20 _Binder<_Unforced, _Fx, _Types...> bind(_Fx&& _Func, _Types&&... _Args) 
    return _Binder<_Unforced, _Fx, _Types...>(_STD forward<_Fx>(_Func), _STD forward<_Types>(_Args)...);


  • 看到是构造了一个_Binder的对象返回,bound参数作为构造函数的参数传入。

    using _Second = tuple<decay_t<_Types>...>; //std::decay_t会移除掉引用属性
    _Compressed_pair<_First, _Second> _Mypair;
    
    constexpr explicit _Binder(_Fx&& _Func, _Types&&... _Args)
            : _Mypair(_One_then_variadic_args_t, _STD forward<_Fx>(_Func), _STD forward<_Types>(_Args)...) 
    
    
  • 也可以看到构造函数中,参数传递给_Mypair成员。到这里结束。

  • 我们再看下调用时:

#define _CALL_BINDER                                                                  \\
    _Call_binder(_Invoker_ret<_Ret>, _Seq, _Mypair._Get_first(), _Mypair._Myval2, \\
        _STD forward_as_tuple(_STD forward<_Unbound>(_Unbargs)...))

template <class... _Unbound>
    _CONSTEXPR20 auto operator()(_Unbound&&... _Unbargs) noexcept(noexcept(_CALL_BINDER)) -> decltype(_CALL_BINDER) 
    return _CALL_BINDER;


  • 看到调用时会用到_CALL_BINDER宏,这里调用_Call_binder函数,并把_Mypair传入,再接下来就会调用到我们的函数并传入bound的参数了。_
  • _总结下就是std::bind首先将传入的参数存放起来,等到要调用bind的函数就将参数传入,而这里没有保存传入参数的引用,只能保存一份参数的拷贝,如果使用我们上边说的“int& a = b”语法,_Binder类中无法保存b的引用,自然调用时传入的就不是b的引用,所以借助reference_wrapper将传入参数的地址保存,使用是通过地址取出来值进而调用函数。

6、std::ref总结

  • 我来给总结下,首先我们讲解了std::ref的一些用法,然后我们讲解std::ref是通过std::reference_wrapper实现,然后我们借助了cppreference上的实现来给大家剖析了他本质就是存放了对象的地址(类似指针的用法😁),还讲解了noexcept等语法,最后我们讲解了下std::bind为什么要使用到reference_wrapper。
  • std::bind使用的是参数的拷贝而不是引用,当可调用对象期待入参为引用时,必须显示利用std::ref来进行引用绑定。
  • 多线程std::thread的可调用对象期望入参为引用时,也必须显式通过std::ref来绑定引用进行传参。

以上是关于C中ref用法的主要内容,如果未能解决你的问题,请参考以下文章

ref 和 out 的用法和区别以及params用法

std::ref用法以及和&引用区别

React Native ref高级用法&&setNativeProps使用

c#中的ref用法

vue中ref的用法

React Refs的多种用法归纳整理