C++学习---STL中nullptr_t的实现原理

时间:2022-12-06 21:54:55

引言

nullptr_t/nullptr是对C语言中NULL的替代,C语言中NULL通常定义为0或(void*)0,无法很好地处理与C++相关的环境,比如类指针的转换、赋值、比较等,容易出现异常。 我们来分析一下C++STL中是如何定义nullptr的,学习STL相关的编程技法。

nullptr_t的定义与实现

代码参考:​​www.aospxref.com/android-13.…​

源码展示

22 _LIBCPP_BEGIN_NAMESPACE_STD
23
24 struct _LIBCPP_TEMPLATE_VIS nullptr_t
25 {
26 void* __lx;
27
28 struct __nat {int __for_bool_;};
29
30 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR nullptr_t() : __lx(0) {}
31 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR nullptr_t(int __nat::*) : __lx(0) {}
32
33 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR operator int __nat::*() const {return 0;}
34
35 template <class _Tp>
36 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
37 operator _Tp* () const {return 0;}
38
39 template <class _Tp, class _Up>
40 _LIBCPP_INLINE_VISIBILITY
41 operator _Tp _Up::* () const {return 0;}
42
43 friend _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR bool operator==(nullptr_t, nullptr_t) {return true;}
44 friend _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR bool operator!=(nullptr_t, nullptr_t) {return false;}
45 };
46
47 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR nullptr_t __get_nullptr_t() {return nullptr_t(0);}
48
49 #define nullptr _VSTD::__get_nullptr_t()
50
51 _LIBCPP_END_NAMESPACE_STD

成员变量---void* __lx

可以看到,实际上nullptr_t的实现还是使用了void*指针,其中​​void* __lx​​就是真正表示的空指针; 又增加了结构体__nat定义,里面只有一个int型变量。

成员函数

默认构造函数

实际上直接将__lx初始化为0,这一点与C语言的处理是一致的。

_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR nullptr_t() : __lx(0) {}

转换构造函数---将int型转换为nullptr_t

实现上还是将__lx初始化为0,只是这里用到了结构体成员指针的概念,​​int __nat::*​​这里实际上指代的是struct __nat中的成员变量,因为后文中并未用到该变量,所以没有填写入参名,完整的参数应该是​​int __nat::*nm​​,nm表示__nat中任意一个成员变量,具体由传参时决定,这里都是int型。

_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR nullptr_t(int __nat::*) : __lx(0) {}

类型转换函数---nullptr_t转换为int型

即空指针nullptr转换为int型得到0。

_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR operator int __nat::*() const {return 0;}

类型转换函数---nullptr_t转换为_Tp*

这里利用模板定义,将nullptr_t转换为任意指针类型,实际上是返回0指针。

template <class _Tp>
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
operator _Tp* () const {return 0;}

类型转换函数---nullptr_t转换为_Tp _Up::*

这个是考虑到类成员指针的情况,将bullptr_t转换为任意类中的任意类型,实际上是返回0指针。

template <class _Tp, class _Up>
_LIBCPP_INLINE_VISIBILITY
operator _Tp _Up::* () const {return 0;}

比较函数

定义为nullptr_t的友元函数,判断两个nullptr_t是否相等,是否不等,逻辑也比较简单。

friend _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR bool operator==(nullptr_t, nullptr_t) {return true;}
friend _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR bool operator!=(nullptr_t, nullptr_t) {return false;}

定义nullptr

实际上我们使用的是nullptr,他是nullptr_t的一个实例,该实例实际上就是使用nullptr_t(0)进行初始化的。

47 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR nullptr_t __get_nullptr_t() {return nullptr_t(0);}
48
49 #define nullptr _VSTD::__get_nullptr_t()

总结

STL中对nullptr_t进行了定义,对int转nullptr_t,nullptr_t转其它指针类型做了准确说明,本质上还是使用(void*)0的方式,但是更加符合C++规范,也避免了隐式转换,保证空指针的行为是可控的,不能够随意参加算数运算,相比起(void*)0的方式更加安全,因此,在C++中,也建议使用nullptr代替NULL表示空指针。