引言
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表示空指针。