前言
在C语言中,我们常常用NULL作为指针变量的初始值,而在C++中,却不建议你这么做。
NULL是什么
在《C++ NULL和0》一文中,我们已经知道了在C中NULL是什么,在C的头文件中,通常定义如下:
但是在C++中,它是这样定义的:
或者你可以在stddef.h看到完整的这段:
1 2 3 4 5 6
| #undef NULL #if defined(__cplusplus) #define NULL 0 #else #define NULL ((void *)0) #endif
|
也就是说,在C++中,NULL不过也是0罢了,把它当成空指针只是一个无可奈何的选择罢了。
那么为什么在C++和C中不一样呢?因为C++中不能将void ✱类型的指针隐式转换成其他指针类型,从下面的例子可以看出来:
1 2 3 4 5 6 7
| #include<iostream> int main() { char p[] = "12345"; int *a = (void*)p; return 0; }
|
编译运行:
1 2 3 4
| $ g+ -o null null.cpp null.cpp: In function 'int main()': null.cpp:5:17: error: invalid conversion from 'void*' to 'int*' [-fpermissive] int *a =(void*)p;
|
所以不能将NULL定义为(void*)0。
nullptr
nullptr并非整型类别,甚至也不是指针类型,但是能转换成任意指针类型。nullptr的实际类型是std:nullptr_t。
为什么该使用nullptr
回到最开始的问题,为什么作为指针的语义,我们应该使用nullptr,而不是NULL。请看下面的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #include<iostream> using namespace std; void test(void *p) { cout<<"p is pointer "<<p<<endl; } void test(int num) { cout<<"num is int "<<num<<endl; } int main() { test(NULL); return 0; }
|
编译运行:
1 2 3 4
| $ g++ -o test test.cpp main.cpp: In function ‘int main()’: main.cpp:16:14: error: call of overloaded ‘test(NULL)’ is ambiguous test(NULL);
|
很不幸,编译报错了,提示我们有二义性,按照《重载函数匹配规则》,两个都可以匹配,因此最终报错。
但是如果我们使用nullptr却不会:
除了这点之外,在C++模板中它还有更好的表现。看下面的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #include<iostream> using namespace std; template<typename Type1,typename ptrType> void test(Type1 fun,ptrType ptr) { fun(ptr); return; } void fun(int *val) { cout<<"fun"<<endl; } int main() { test(fun,NULL); return 0; }
|
编译报错了:
1 2
| main.cpp:8:8: error: invalid conversion from ‘long int’ to ‘int*’ [-fpermissive] fun(ptr);
|
很显然NULL被推导为long int,而不是空指针,因而导致函数类型不匹配而报错。但是如果我们用nullptr就不会有上面的问题。
总结
如果你想表示空指针,那么使用nullptr,而不是NULL。
注:nullptr在C++ 11中才出现。