- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章解析C++11的std::ref、std::cref源码由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
本文是基于gcc-4.9.0的源代码进行分析,std::ref和std::cref是C++11才加入标准的,所以低版本的gcc源码是没有这两个的,建议选择4.9.0或更新的版本去学习,不同版本的gcc源码差异应该不小,但是原理和设计思想的一样的,下面给出源码下载地址 http://ftp.gnu.org/gnu/gcc 。
C++本身就有引用(&),那为什么C++11又引入了std::ref(或者std::cref)呢? 主要是考虑函数式编程(如std::bind)在使用时,是对参数直接拷贝,而不是引用。下面是一个简单的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
#include <functional>
#include <iostream>
void
fun(
int
& n1,
int
& n2,
const
int
& n3)
{
std::cout <<
"In function: "
<< n1 <<
' '
<< n2 <<
' '
<< n3 <<
'\n'
;
++n1;
// increments the copy of n1 stored in the function object
++n2;
// increments the main()'s n2
// ++n3; // compile error
std::cout <<
"In function end: "
<< n1 <<
' '
<< n2 <<
' '
<< n3 <<
'\n'
;
}
int
main()
{
int
n1 = 1, n2 = 1, n3 = 1;
std::function<
void
()> fff = std::bind(f, n1, std::ref(n2), std::cref(n3));
std::cout <<
"Before function: "
<< n1 <<
' '
<< n2 <<
' '
<< n3 <<
'\n'
;
fff();
std::cout <<
"After function: "
<< n1 <<
' '
<< n2 <<
' '
<< n3 <<
'\n'
;
}
|
运行结果:
Before function: 1 1 1 In function: 1 1 1 In function end: 2 2 1 After function: 1 2 1 。
从上面的例子中可以看到,执行完fff,n1的值仍然是1,n2的值已经改变,这说明std::bind使用的是参数的拷贝而不是引用,这也就是为什么C++11要引入std::ref和std::cref的原因了,接下来分析std::ref的实现(std::cref不作分析,因为和std::ref的位移差别只是引用变成了const而已) 。
std::ref位于libstdc++-v3\include\std\functional中 。
1
2
3
4
5
6
7
8
9
10
|
template
<
typename
_Tp>
inline
reference_wrapper<_Tp> ref(_Tp& __t) noexcept
{
return
reference_wrapper<_Tp>(__t); }
template
<
typename
_Tp>
void
ref(
const
_Tp&&) =
delete
;
template
<
typename
_Tp>
inline
reference_wrapper<_Tp> ref(reference_wrapper<_Tp> __t) noexcept
{
return
ref(__t.get()); }
|
从源代码中可以看出:
std::reference_wrapper
std::reference_wrapper
对象,接下来分析std::reference_wrapper
的实现
std::reference_wrapper位于libstdc++-v3\include\std\functional中 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
template
<
typename
_Tp>
class
reference_wrapper :
public
_Reference_wrapper_base<
typename
remove_cv<_Tp>::type>
{
_Tp* _M_data;
public
:
typedef
_Tp type;
reference_wrapper(_Tp& __indata) noexcept
:_M_data(std::__addressof(__indata))
{
}
reference_wrapper(_Tp&&) =
delete
;
reference_wrapper(
const
reference_wrapper<_Tp>& __inref) noexcept
:_M_data(__inref._M_data)
{
}
reference_wrapper& operator=(
const
reference_wrapper<_Tp>& __inref) noexcept
{
_M_data = __inref._M_data;
return
*
this
;
}
operator _Tp&()
const
noexcept
{
return
this
->get(); }
_Tp& get()
const
noexcept
{
return
*_M_data; }
template
<
typename
... _Args>
typename
result_of<_Tp&(_Args&&...)>::type
operator()(_Args&&... __args)
const
{
return
__invoke(get(), std::forward<_Args>(__args)...);
}
};
|
从源代码中可以获得以下信息:
std::_Reference_wrapper_base
_M_data
,类型为所引用类型的指针std::__addressof
函数,获得了指向引用参数的指针,并赋值给了_M_data(这也是为什么不支持右值引用的原因,因为取不到对应的地址),std::__addressof
实现如下:
1
2
3
4
5
6
7
8
|
// 位于**libstdc++-v3\include\bits\move.h**中
// 借助reinterpret_cast能任意转换类型的特性来将<code>_Tp&</code>转为<code>_Tp*</code>
//(转换过程编译器不保证正确,要由程序员来保证转换过程不出错,虽然标准库用了很多这样的特殊技巧,但是实际开发中这些少用为好)
template
<
typename
_Tp>
inline
_Tp* __addressof(_Tp& __r) _GLIBCXX_NOEXCEPT
{
return
reinterpret_cast
<_Tp*>(&
const_cast
<
char
&>(
reinterpret_cast
<
const
volatile
char
&>(__r)));
}
|
std::remove_cv位于libstdc+±v3\include\std\type_traits中 。
分析std::_Reference_wrapper_base之前先看一下std::remove_cv的实现 其实从std::remove_cv存在于type_traits文件这一点就可以大致推断出,std::remove_cv使用了模板元技术,模板元的主要思想为:利用模板特化机制实现编译期条件选择结构,利用递归模板实现编译期循环结构,模板元程序则由编译器在编译器解释运行,但是其也有明显的优缺点,优点是运行时速度极快,缺点是程序很难看懂,容易劝退初学者,这里不对其做深入分析,知道是这样一个东西就行,有兴趣的可以去查阅专业的C++书籍去了解其中的奥秘 源代码如下,作用是将模板_Tp的const和voaltile属性分离,这样的话使用::value就可以得到没有const、volatile的类型了 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
/// remove_const
template
<
typename
_Tp>
struct
remove_const
{
typedef
_Tp type; };
template
<
typename
_Tp>
struct
remove_const<_Tp
const
>
{
typedef
_Tp type; };
/// remove_volatile
template
<
typename
_Tp>
struct
remove_volatile
{
typedef
_Tp type; };
template
<
typename
_Tp>
struct
remove_volatile<_Tp
volatile
>
{
typedef
_Tp type; };
/// remove_cv
template
<
typename
_Tp>
struct
remove_cv
{
typedef
typename
remove_const<
typename
remove_volatile<_Tp>::type>::type type;
};
|
std::_Reference_wrapper_base位于libstdc++-v3\include\std\functional中 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
template
<
typename
_Tp>
struct
_Reference_wrapper_base
:_Reference_wrapper_base_impl<
__has_argument_type<_Tp>::value,
__has_first_argument_type<_Tp>::value
&& __has_second_argument_type<_Tp>::value,
_Tp>
{};
template
<
typename
_Res,
typename
_T1>
struct
_Reference_wrapper_base<_Res(_T1)> : unary_function<_T1, _Res>
{};
template
<
typename
_Res,
typename
_T1>
struct
_Reference_wrapper_base<_Res(_T1)
const
> : unary_function<_T1, _Res>
{};
template
<
typename
_Res,
typename
_T1>
struct
_Reference_wrapper_base<_Res(_T1)
volatile
> : unary_function<_T1, _Res>
{};
template
<
typename
_Res,
typename
_T1>
struct
_Reference_wrapper_base<_Res(_T1)
const
volatile
> : unary_function<_T1, _Res>
{};
// - a function type (binary)
template
<
typename
_Res,
typename
_T1,
typename
_T2>
struct
_Reference_wrapper_base<_Res(_T1, _T2)> : binary_function<_T1, _T2, _Res>
{};
template
<
typename
_Res,
typename
_T1,
typename
_T2>
struct
_Reference_wrapper_base<_Res(_T1, _T2)
const
> : binary_function<_T1, _T2, _Res>
{};
template
<
typename
_Res,
typename
_T1,
typename
_T2>
struct
_Reference_wrapper_base<_Res(_T1, _T2)
volatile
> : binary_function<_T1, _T2, _Res>
{};
template
<
typename
_Res,
typename
_T1,
typename
_T2>
struct
_Reference_wrapper_base<_Res(_T1, _T2)
const
volatile
> : binary_function<_T1, _T2, _Res>
{};
template
<
typename
_Res,
typename
_T1>
struct
_Reference_wrapper_base<_Res(*)(_T1)> : unary_function<_T1, _Res>
{};
template
<
typename
_Res,
typename
_T1,
typename
_T2>
struct
_Reference_wrapper_base<_Res(*)(_T1, _T2)> : binary_function<_T1, _T2, _Res>
{};
template
<
typename
_Res,
typename
_T1>
struct
_Reference_wrapper_base<_Res (_T1::*)()> : unary_function<_T1*, _Res>
{};
template
<
typename
_Res,
typename
_T1,
typename
_T2>
struct
_Reference_wrapper_base<_Res (_T1::*)(_T2)> : binary_function<_T1*, _T2, _Res>
{};
template
<
typename
_Res,
typename
_T1>
struct
_Reference_wrapper_base<_Res (_T1::*)()
const
> : unary_function<
const
_T1*, _Res>
{};
template
<
typename
_Res,
typename
_T1,
typename
_T2>
struct
_Reference_wrapper_base<_Res (_T1::*)(_T2)
const
> : binary_function<
const
_T1*, _T2, _Res>
{};
template
<
typename
_Res,
typename
_T1>
struct
_Reference_wrapper_base<_Res (_T1::*)()
volatile
> : unary_function<
volatile
_T1*, _Res>
{};
template
<
typename
_Res,
typename
_T1,
typename
_T2>
struct
_Reference_wrapper_base<_Res (_T1::*)(_T2)
volatile
> : binary_function<
volatile
_T1*, _T2, _Res>
{};
template
<
typename
_Res,
typename
_T1>
struct
_Reference_wrapper_base<_Res (_T1::*)()
const
volatile
> : unary_function<
const
volatile
_T1*, _Res>
{};
template
<
typename
_Res,
typename
_T1,
typename
_T2>
struct
_Reference_wrapper_base<_Res (_T1::*)(_T2)
const
volatile
> : binary_function<
const
volatile
_T1*, _T2, _Res>
{};
|
从代码中可以看出,std::_Reference_wrapper_base继承于std::unary_function或者std::binary_function,在实际编程中对std::reference_wrapper的作用不大,除非引用的是一个函数对象,所以在这里就不分析它的具体作用了,大家直接去查一下unary_function和binary_function是啥东西就行了 。
std::ref和std::cref在函数式编程中的作用是非常大的,C++11后的源代码中多次使用到了它们。而std::ref和std::cref事实上是模板函数,返回值是一个std::reference_wrapper对象,而std::reference_wrapper虽然是一个对象,可是他却能展现出和普通引用类似的效果,这点和前一篇文章讲的智能指针如出一辙(事实上标准库大多是这样设计的,这也是运算符重载存在的一个重要意义)。当我们在函数式编程(如std::bind)中需要对参数进行引用传递时,只需要用std::ref或std::cref修饰该引用即可 。
到此这篇关于解析C++11的std::ref、std::cref源码的文章就介绍到这了,更多相关C++11 std::ref、std::cref 内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。
原文链接:https://blog.csdn.net/weixin_43798887/article/details/116562336 。
最后此篇关于解析C++11的std::ref、std::cref源码的文章就讲到这里了,如果你想了解更多关于解析C++11的std::ref、std::cref源码的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我想读取帖子的数据并获取用户 key ,然后通过它进行搜索并同时获取用户数据,我尝试过,但它后退了一步,直到它才显示用户名我执行任何其他操作 这是帖子和经过身份验证的用户的 Firebase 实时数据
您知道是否有办法将 js ref 和 css ref 作为单个 ref 包含在 html 中?通常这些 ref 单独包含在 html head 中,但我的经理想知道下游消费者是否有一种简化的方法将这些
我正在使用 Swing+Clojure 开发一个 GUI 应用程序,它需要各种可变数据(例如滚动位置、用户数据、文件名、选定的工具选项等)。 我至少可以看到三种不同的处理这组数据的方式: 创建对所有数
我正在尝试通过 React 使用 ref 属性。我的浏览器出现奇怪的错误,但我无法弄清楚问题出在哪里。谁能向我解释一下为什么我会收到此错误: Error: Invariant Violation: a
在我的程序中,我有模板类,这些模板类主要是用于特殊目的 std::function 的包装器。最小的例子是: template class Foo { public: exp
如果被引用为参数的对象在函数中被修改,是否使用 ref 有关系吗?下面两个函数有区别吗? void DisposeObject(ClassThing c) { c.Dispose(); } vo
尝试将大型但线性的 svn 存储库迁移到 git。 svn 存储库没有标准布局(主干、分支、标签)...只有主干的一个目录。 Ubuntu 12.4 LTS,git 1.7.9.5。 $ git sv
您现在如何设置动态引用? 我收到一个错误 cannot set property of 'test' undefined ,如果我使用 this.someRef['test'] = ref;}/>
试图理解 gerrit 中的 refs/for/refs/* 功能。这个问题与 refs/for/master 无关。 我们什么时候可以使用这个 refs/for/refs/* 功能。 有人可以为此解
我以不同的方式调用 4 种方法时得到不同的结果: static void Main(string[] args) { var emp = new Employee { Name = "ABC"
假设我有以下内容: var t = typeof(Foo).MakeByRefType(); 有没有办法将结果转换回typeof(Foo)? 老实说,我发现的唯一方法是: var t = typeof
我以下列方式使用 ref。那么当在第 5 种方法中创建一个新对象时,是否会一直访问 main 方法中的原始 emp 并在那里创建一个新对象? 如果是,有没有一种方法可以实现相同的功能而无需多次迭代,即
我在文档的 html 标签内有一些文本。文字看起来像这样 I need this text <ref> Some unwanted text </ref> I need thi
一些背景: 前几天我遇到了一些事情,这让我开始思考嵌套函数调用中的重载解析。考虑以下代码: #include void printer(const int &a) { std::cout <<
如果直接从 this.refs 获取元素对象,那么为什么要使用 ReactDOM.findDOMNode? var HelloMessage = React.createClass({ click:f
我在这里做错了什么,或者从 C# 7.2 开始,不支持通过 ref 返回并允许设置的索引器? 作品: public ref byte this[int index] { get { r
看来我现在几乎每天都在这里问问题。我不确定这是好事还是坏事... 今天的“WTF flavor ”涉及我在使用来自 NI Measurement Studio 对象的函数时完全和完全无能为力。与我之前
这个问题在这里已经有了答案: Does foreach() iterate by reference? (10 个答案) Alternative to using ref in foreach? (
给定一个函数声明 dynamic DoSomething(dynamic inputObject) 我可以用枚举调用它作为inputObject: MyEnum myEnum; myEnum = Do
如果我将数组传递给函数并在函数内对数组进行更改,则函数外部存在的数组会反射(reflect)这些效果。例如: var myArr = [1, 2, 3]; function popAll(arr) {
我是一名优秀的程序员,十分优秀!