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.
C++11: reference_wrapper的更多相关文章
- 地区sql
/*Navicat MySQL Data Transfer Source Server : localhostSource Server Version : 50136Source Host : lo ...
- C++11的一些新特性
3.1.9崭新的Template特性 Variadic Template 可变参数模板 void print() { } template <typename T, typename… Type ...
- C++11包装引用
[C++11包装引用] 我们可以通过实体化样板类 reference_wrapper 得到一个包装引用 (wrapper reference).包装引用类似于一般的引用.对于任意对象,我们可以通过模板 ...
- c++11 : range-based for loop
0. 形式 for ( declaration : expression ) statement 0.1 根据标准将会扩展成这样的形式: 1 { 2 auto&& __ra ...
- [转载] C++11新特性
C++11标准发布已有一段时间了, 维基百科上有对C++11新标准的变化和C++11新特性介绍的文章. 我是一名C++程序员,非常想了解一下C++11. 英文版的维基百科看起来非常费劲,而中文版维基百 ...
- C++11新特性之八——函数对象function
详细请看<C++ Primer plus>(第六版中文版) http://www.cnblogs.com/lvpengms/archive/2011/02/21/1960078.html ...
- 引用传参与reference_wrapper
本文是<functional>系列的第3篇. 引用传参 我有一个函数: void modify(int& i) { ++i; } 因为参数类型是int&,所以函数能够修改传 ...
- C++11<functional>深度剖析
自C++11以来,C++标准每3年修订一次.C++14/17都可以说是更完整的C++11:即将到来的C++20也已经特性完整了. C++11已经有好几年了,它的年龄比我接触C++的时间要长10倍不止吧 ...
- WinForm 天猫2013双11自动抢红包【源码下载】
1. 正确获取红包流程 2. 软件介绍 2.1 效果图: 2.2 功能介绍 2.2.1 账号登录 页面开始时,会载入这个网站:https://login.taobao.com/member/login ...
随机推荐
- 安卓 应用app启动过程
韩梦飞沙 yue31313 韩亚飞 han_meng_fei_sha 313134555@qq.com 从用户点击 Launcher 上的 App 图标,到显示出 App 界面时主要发生的事情.知晓以 ...
- 【BZOJ 4570】【SCOI 2016】妖怪
http://www.lydsy.com/JudgeOnline/problem.php?id=4570 对于每个妖怪的两个值,看成二位平面上的一个点的横纵坐标(x,y). 因为只关心a/b,所以设经 ...
- SD 一轮集训 day4 圣城鼠
非常强的构造题. 很显然的是我们要构造一个类似菊花图的东西,因为这样的话两点之间路径的点数会非常少,很容易满足第二个条件. 但是因为直接菊花图的话会不满足第一个条件,,,所以我们可以构造一个类菊花图. ...
- 计算标准差 Exercise07_11
import java.util.Scanner; /** * @author 冰樱梦 * 时间:2018年下半年 * 题目:计算标准差 * */ public class Exercise07_11 ...
- 【常见加密方法】Base64编码&Tea算法简介
Base64编码 [Base64编码是什么] Base64是一种基于64个可打印字符来表示二进制数据的表示方法. ——维基百科 Base64,顾名思义,是基于64种可视字符的编码方式.这64种符号由A ...
- CentOS下OpenVPN实现公网IP映射到内网(iptables转发功能)(转)
说明:这种方案的实现前提是必须要有一台拥有公网IP的电脑,OpenVPN搭建过程很普通,关键技术在于iptables的转发.搭建教程可能有点旧了,可以只看iptables的关键点技术. 方案背景: 公 ...
- 控制台+Owin搭建WebAPI接口服务
当没有iis环境.想快速启动几个api接口测试又觉得新建一个api项目麻烦?来使用控制台做宿主,快速改几个api测试吧! 1.新建控制台项目 2.安装以下相关依赖 Microsoft.AspNet.W ...
- iOS-Runtime、对象模型、消息转发
Objective-C只是在C语言层面上加了些关键字和语法.真正让Objective-C如此强大的是它的运行时.它很小但却很强大.它的核心是消息分发. Message 执行一个方法,有些语言.编译器会 ...
- iOS中nil、Nil、NULL、NSNull详解
nil nil 是 ObjC 对象的字面空值,对应 id 类型的对象,或者使用 @interface 声明的 ObjC 对象. 例如: NSString *someString = nil; NSUR ...
- JStorm模型设计
问题描述 1.在流式计算中经常需要对一批的数据进行汇总计算,类似SQL中的GROUP BY.在用JStorm来实现这一条简单的SQL时,面对的是一条一条的数据库变化的消息(这里需要保证有序消费),其实 ...