zoukankan      html  css  js  c++  java
  • C++11: reference_wrapper

    https://oopscenities.net/2012/08/09/reference_wrapper/

    Look at this piece of code:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #include <iostream>
    #include <functional>
     
    using namespace std;
    using namespace std::placeholders;
     
    void add(int a, int b, int& r)
    {
        r = a + b;
    }
     
    int main()
    {
        int result = 0;
         
        auto f = bind(add, _1, 20, result);
         
        f(80);
         
        cout << result << endl;
        return 0;
    }

    This program supposedly adds 80 to 20 and prints the result; it compiles perfectly but when you execute it; you get…. 0!

    Why?

    Because the bind method receives its parameters as parameters-by-value and the “result” variable is copied before being passed to the bound function add. Why?
    Because bind does not know if the parameters will still be valid when the actual invocation will be performed (remember, you could pass a function object to other function passing local variables as arguments and invoking it from there).

    The solution? Pretty simple:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    int main()
    {
        int result = 0;
         
        auto f = bind(add, _1, 20, ref(result));
         
        f(80);
         
        cout << result << endl;
        return 0;
    }

    I added the function ref that sends our parameter as a reference to the bound function.

    What does this function ref do?

    It is a template function that returns a reference_wrapper object. A reference_wrapper is a class template that wraps a reference in a concrete object.

    Actually you could do something like:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    int main()
    {
        int result = 0;
         
        reference_wrapper<int> result_ref(result);
        auto f = bind(add, _1, 20, result_ref);
         
        f(80);
         
        cout << result << endl;
        return 0;
    }

    and everything would continue working as expected.

    As you can see, you can pass the reference_wrapper by value and everything will work because its copy constructor copies the reference (actually, the reference_wrapper implementations do not store a reference but a pointer to the data being referenced, but their methods expose it as a reference).

    Other nice usage of this would be in cases where you need to have a container of references (the actual objects are stored in other container or in other place and you do not need/want to have copies or pointers to them). For example, you have these classes:

    1
    2
    class A { };
    class B : public A { };

    And you want to have at the same time local variables pointing to them and you want them stored in a container:

    1
    2
    3
    4
    5
    6
    7
    int main()
    {
      A a, c;
      B b, d;
     
      vector<A> v = { a, b, c, d };
    }

    Good? No! Bad at all! You are storing instances of class A in your vector. All the instances of B will be copied as instances of A (losing their specific attributes and all the polymorphic behavior and so on).

    One solution? Storing pointers:

    1
    2
    3
    4
    5
    6
    7
    int main()
    {
      A a, c;
      B b, d;
     
      vector<A*> v = { &a, &b, &c, &d };
    }

    It works, but it is not evident for the user of the container if s/he will be in charge of freeing the objects or not.

    Other solution? Using references:

    1
    2
    3
    4
    5
    6
    7
    int main()
    {
      A a, c;
      B b, d;
     
      vector<A&> v = { a, b, c, d };
    }

    Looks nice, but it does not compile; because you cannot specify reference types in a vector.

    Real solution: Using reference_wrappers:

    1
    2
    3
    4
    5
    6
    7
    int main()
    {
      A a, c;
      B b, d;
     
      vector<reference_wrapper<A>> v = { a, b, c, d };
    }

    Someone could argue: In which scenario is this thing useful?

    If you create a UI frame using Java Swing, you probably create a subclass of the JFrame class, will specify your visual components as member variables and you will also add them into the JFrame’s component list. Implementing something similar in C++ using reference_wrappers would be quite elegant.

  • 相关阅读:
    PSP ISO游戏运行必备工具:ISO TOOL 1.970 功能一览&图文教程
    Linux防火墙(原书第3版) 电子书籍
    iptables的相关概念和数据包的流程(图)
    oracle数据库远程连接服务器配置tnsnames
    编程感悟
    工作任务三 打印表单数据
    UltraWebTree的使用心得
    DropDownList应用
    使用UltraWebTree时,如何在刷新后展开之前选中的节点,并绑定相关数据
    webgrid 添加行是不允许相同
  • 原文地址:https://www.cnblogs.com/diegodu/p/6868553.html
Copyright © 2011-2022 走看看