资讯专栏INFORMATION COLUMN

五、C++11新特性: 指针空值--nullptr及nullptr_t

eechen / 1612人阅读

摘要:和宋体标准不仅定义了指针空值常量,也定义了其指针空值类型,也就表示了指针空值类型并非仅有一个实例。标准严格规定了数据间的关系。


五、C++ 11 指针空值—nullptr

5.1、引入nullptr的意义:

在C++程序开发中,为了提高代码的健壮性,一般会在定义指针的同时会完成初始化操作(避免出现野指针),在指针指向尚未明确的情况下,都会给指针初始化为空指针。在C++98/03标准中,将一个指针初始化为空指针的方式有两种:

char *my_ptr = 0;char *my_ptr = NULL;

在底层源码中 NULL 这个宏是这样定义的:

#ifndef NULL#ifdef __cplusplus#define NULL 0#else#define NULL ((void *)0)#endif#endif

可以看出,NULL可能被定义为字面常量0,或者是定义为无类型指针(void*)0
原因: 由于 C++ 中, void *类型无法隐式转换为其他类型的指针,此时使用 0 代替 ((void *)0),用于解决空指针的问题。这个 0(0x0000 0000)表示的就是虚拟地址空间中的 0 地址,这块地址是只读的。但是无论采用什么样的定义方式,我们在使用空值的指针时,都不可避免地会遇到一些麻烦;

如下代码:

#include using namespace std;void fun(char *c){    cout << "void func(char *c)" << endl;}void fun(int i){    cout << "void func(int i)" << endl;}int main(){    // 想要调用重载函数 void func(char *p)    func(NULL);  //注:如果使用gcc编译,NULL转化为内部标识 __null,该语句会编译失败         // 想要调用重载函数 void func(int i)    func(0);        	func((char*)0);    return 0;}

输出:

void func(int i)void func(int i)void func(char *c)

虽然调用func(NULL); 最终链接到的还是void func(int p) 和预期是不一样的;
原因: C++ 中将NULL定义为字面常量 0,并不能保证在所有场景下都能很好的工作,比如,函数重载时,NULL 和 0 无法区分;

在C++11新标准中,出于兼容性的考虑,字面常量0的二义性并没有被消除;但是新标准为二义性给出了新的答案,就是使用 nullptr;在C++11 新标准中, nullptr是一个所谓“指针空值类型”的常量;指针空值类型被命名为 nullptr_t

可以在支持 nullptr的头文件(csddef)中找到如下定义:

typedef decltype(nullptr) nullptr_t;

使用 nullptr_t的时候必须#include(#include有些头文件也会间接#include,比如),而 nullptr则不用。

大概就是由于 nullptr是关键字,而 nullptr_t是通过 decltype推导而来的缘故。
对上述程序进行修改:

#include using namespace std;void fun(char *c){    cout << "void func(char *c)" << endl;}void fun(int i){    cout << "void func(int i)" << endl;}int main(){    //调用重载函数 void func(char *p)    func(nullptr);           //调用重载函数 void func(int i)    func(0);        return 0;}

结果:

void func(char *c)void func(int i)

可以看出,nullptr 无法隐式转换为整形,但是可以隐式匹配指针类型。在 C++11 标准下,相比NULL和 0,使用 nullptr初始化空指针可以令我们编写的程序更加健壮。

5.2、nullptr和nullptr_t

C++11标准不仅定义了指针空值常量nullptr,也定义了其指针空值类型nullptr_t,也就表示了指针空值类型并非仅有nullptr一个实例。通常情况下,也可以通过nullptr_t来声明一个指针空值类型的变量(即使看起来用途不大)。

除去nullptrnullptr_t以外,C++中还存在各种内置类型。C++11标准严格规定了数据间的关系。常见的规则简单地列在了下面:

①、所有定义为nullptr_t类型的数据都是等价的,行为也是完全一致。

②、nullptr_t类型数据可以隐式转换成任意一个指针类型。

③、nullptr_t类型数据不能转换为非指针类型,即使使用reinterpret_cast()的方式也是不可以的。

④、 nullptr_t类型数据不适用于算术运算表达式。

⑤、nullptr_t类型数据可以用于关系运算表达式,但仅能与nullptr_t类型数据或者指针类型数据进行比较,当且仅当关系运算符为==、<=、>=等时返回true。

5.3、关于nullptr规则的一些讨论

①、在C++11标准中,nullptr类型数据所占用的内存空间大小跟void*相同的,即:

sizeof(nullptr_t) == sizeof(void*)

注:nullptr是否是(void *)0的一个别名?

不是,尽管两者看起来很相似,都可以被转换为任何类型的指针,但两者在语法层面有着不同的内涵。nullptr是一个编译时期的常量,它的名字是一个编译时期的关键字,能够为编译器所识别。而(void*)0只是一个强制转换表达式,其返回的也是一个 void *指针类型。最为重要的是,在C++语言中,nullptr到任何指针的转换是隐式的,而 (void*)0则必须经过类型转换后才能使用。

可以关注公众号:Kevin的嵌入式学习站,创作不易,但您的点赞、关注、收藏就是对我最大的鼓励!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/123502.html

相关文章

  • C++入门篇(2)之引用,内联函数,auto和范围遍历

    文章目录 前言extern C引用1.概念2.语法3.引用特性4.常量引用5.引用做函数返回值6.引用注意点7.传值、传引用效率比较 内联函数1.概念2.特性 auto关键字1.概念2.auto的使用细则3.auto不能推导的场景 基于范围的for循环(C++11)使用条件 指针空值nullptr 前言 承接上文入门篇1,博主这次将会继续更新以下内容:extern ,引用 ,内联, a...

    wangtdgoodluck 评论0 收藏0
  • C++】初窥门径---入门篇

    摘要:在大型的工程中,自己定义的变量函数,类名与其他人定义的相冲突等问题。使用标准输出控制台和标准输入键盘时,必须包含头文件以及标准命名空间。缺省参数概念缺省参数是声明或定义函数时为函数的参数指定一个默认值。 目录 前言 1.命名空间 1.1命名空间定义 1.2 命名空间使用 2. C++的输入和...

    不知名网友 评论0 收藏0
  • C++ 开发 PHP 7 扩展之原生函数定义

    摘要:第一步打开项目下的文件,在文件中输入我们的函数的原型声明代码。这行代码注册一个原型为的函数,当这个函数被执行的时候,我们的函数将被运行时调用。原文地址开发扩展之原生函数定义 在上一篇中我们在hellozapi扩展中我们定义了几个常量,但是一个有用的扩展,必须得有函数,没有函数的扩展啥用没有,如果您觉得定义函数很难的话,您又错了,zendAPI就是为了让您生活变得美好而生的,而不会让事情...

    asce1885 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<