引言
nullptr_t/nullptr 是对 C 语言中 NULL 的替代,C 语言中 NULL 通常定义为 0 或(void*)0,无法很好地处理与 C++相关的环境,比如类指针的转换、赋值、比较等,容易出现异常。我们来分析一下 C++STL 中是如何定义 nullptr 的,学习 STL 相关的编程技法。
nullptr_t 的定义与实现
代码参考:http://www.aospxref.com/android-13.0.0_r3/xref/external/libcxx/include/__nullptr
源码展示
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 表示空指针。
评论