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.

C++11: reference_wrapper的更多相关文章

  1. 地区sql

    /*Navicat MySQL Data Transfer Source Server : localhostSource Server Version : 50136Source Host : lo ...

  2. C++11的一些新特性

    3.1.9崭新的Template特性 Variadic Template 可变参数模板 void print() { } template <typename T, typename… Type ...

  3. C++11包装引用

    [C++11包装引用] 我们可以通过实体化样板类 reference_wrapper 得到一个包装引用 (wrapper reference).包装引用类似于一般的引用.对于任意对象,我们可以通过模板 ...

  4. c++11 : range-based for loop

    0. 形式 for ( declaration : expression ) statement 0.1 根据标准将会扩展成这样的形式: 1   { 2     auto&& __ra ...

  5. [转载] C++11新特性

    C++11标准发布已有一段时间了, 维基百科上有对C++11新标准的变化和C++11新特性介绍的文章. 我是一名C++程序员,非常想了解一下C++11. 英文版的维基百科看起来非常费劲,而中文版维基百 ...

  6. C++11新特性之八——函数对象function

    详细请看<C++ Primer plus>(第六版中文版) http://www.cnblogs.com/lvpengms/archive/2011/02/21/1960078.html ...

  7. 引用传参与reference_wrapper

    本文是<functional>系列的第3篇. 引用传参 我有一个函数: void modify(int& i) { ++i; } 因为参数类型是int&,所以函数能够修改传 ...

  8. C++11<functional>深度剖析

    自C++11以来,C++标准每3年修订一次.C++14/17都可以说是更完整的C++11:即将到来的C++20也已经特性完整了. C++11已经有好几年了,它的年龄比我接触C++的时间要长10倍不止吧 ...

  9. WinForm 天猫2013双11自动抢红包【源码下载】

    1. 正确获取红包流程 2. 软件介绍 2.1 效果图: 2.2 功能介绍 2.2.1 账号登录 页面开始时,会载入这个网站:https://login.taobao.com/member/login ...

随机推荐

  1. Linux用户密码文件/etc/shadow相关

    (1).密码文件 [root@xuexi ~]# head -3 /etc/shadow root:$6$kcgcu794R0VP3fDL$aYN8XUbtWvZ4QQtT2xVW.N2CgE3YLP ...

  2. luogu P2485 [SDOI2011]计算器

    题目描述 你被要求设计一个计算器完成以下三项任务: 1.给定y.z.p,计算y^z mod p 的值: 2.给定y.z.p,计算满足xy ≡z(mod p)的最小非负整数x: 3.给定y.z.p,计算 ...

  3. [BZOJ2286][SDOI2011]消耗战(虚树DP)

    2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 4998  Solved: 1867[Submit][Statu ...

  4. HDU 5967 小R与手机(动态树)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5967 [题目大意] 给出一张图,每个点仅连一条有向边,或者不连, 要求查询在可更改有向边的情况每个 ...

  5. 【推导】AtCoder Regular Contest 082 D - Derangement

    题意:给你一个排列a,每次可以交换相邻的两个数.让你用最少的交换次数使得a[i] != i. 对于两个相邻的a[i]==i的数,那么一次交换必然可以使得它们的a[i]都不等于i. 对于两个相邻的,其中 ...

  6. (原创)Stanford Machine Learning (by Andrew NG) --- (week 3) Logistic Regression & Regularization

    coursera上面Andrew NG的Machine learning课程地址为:https://www.coursera.org/course/ml 我曾经使用Logistic Regressio ...

  7. 1.创建spring cloud父工程和子模块

    创建父工程 idea创建父工程 idea创建一个工程.父工程管理公共资源 添加子模块 选择添加到父工程里面spring_cloud_parent 相应的子模块添加到父工程的pom.xml文件里

  8. windows和linux下杀死Tomcat进程,解决端口占用

    windows和linux下解决Tomcat进程 windows下启动Tomcat报错,8080端口号被占用,报错信息如下 两种解决方法,一种是关闭了这个端口号,另外一种是修改Tomcat下的serv ...

  9. Word中正文两栏表格通栏排版

    如图所示,需要在插入表格的地方插入连续分节符,这是word2013,在插入里面只有分页符 如果直接插入的话表格上下的分节符会分栏,那样表格会歪曲, 可以上面一段和下面一段设置成通栏,然后中间插入表格, ...

  10. openssh相关

    openssh相关    DSA RSA,非对称加密,产生公钥.私钥,前者存放在remote,后者存放在local,ssh-keygen产生公钥私钥时,提示输入私钥密码,防止私钥泄露被盗    ssh ...