众所周知,C语言使用NULL常量来表示空指针,为什么C++11还要增加新的nullptr来表示空指针呢?
1,我们首先查看NULL的定义:
#if defined (_STDDEF_H) || defined (__need_NULL)
#undef NULL /* in case has defined it. */
#ifdef __GNUG__
#define NULL __null
#else /* G++ */
#ifndef __cplusplus
#define NULL ((void *)0)
#else /* C++ */
#define NULL 0
#endif /* C++ */
#endif /* G++ */
#endif /* NULL not defined and or need NULL. */
#undef __need_NULL
从上面的定义可以看出,如果定义了__GNUG__,编译器NULL其实就是__null,__null是编译器相关的行为(要么是常量0,要么是 (void *)0),有待进一步研究确认。
因此,在C语言中,如下定义都是合法的:
int a = NULL;
char b = NULL;
int *ptr = NULL;
2,在C++中,考虑如下重载示例:
void overloaded(int value) {
std::cout <<"int value" <}
void overloaded(int *ptr) {
std::cout <<"int *ptr" <}
int main() {
overloaded(NULL); // 歧义&#xff0c;因为NULL既可以是常量0&#xff0c;也可以是 void*指针。
return 0;
}
由于C&#43;&#43;支持函数重载&#xff0c;此时NULL的定义就会带来歧义&#xff0c;当我们调用overloaded(NULL)&#xff1b;的时候&#xff0c;编译器无法确认&#xff0c;到底是把NULL作为常量0还是作为 (void *)0&#xff0c;因此编译无法通过。
为了解决这个问题&#xff0c;C&#43;&#43;11引入了nullptr常量&#xff0c;该常量是std::nullptr_t类型。std::nullptr_t类型可以转换为任意指针类型(类似于void *&#xff0c;也可以转换为任意指针类型)&#xff0c;同时也可以转换为bool类型(用以支持条件判断 !ptr)&#xff0c;但是不能转换成整型类型。这样便消除了上面的重载歧义。
overloaded(nullptr); // ok&#xff0c;调用void overloaded(int *ptr);版本
转换成bool类型示例如下&#xff1a;
int main() {
std::nullptr_t ptr &#61; nullptr;
if (!ptr) { // std::nullptr_t类型转换成bool类型
std::cout <<"nullptr" <}
return 0;
}
3&#xff0c;当然&#xff0c;nullptr只是解决了整型和指针类型的重载问题&#xff0c;对于两个不同指针类型的重载函数&#xff0c;nullptr无法区分出来&#xff1a;
void overloaded(int *ptr) {
std::cout <<"int *ptr" <}
void overloaded(char *ptr) {
std::cout <<"char *ptr" <}
int main() {
overloaded(nullptr); // 歧义&#xff0c;依然无法区分 int *和 char *
return 0;
}
这时候&#xff0c;可以使用std::nullptr_t类型&#xff0c;如下&#xff1a;
void overloaded(int *ptr) {
std::cout <<"int *ptr" <}
void overloaded(char *ptr) {
std::cout <<"char *ptr" <}
void overloaded(std::nullptr_t ptr) {
std::cout <<"std::nullptr_t ptr" <}
int main() {
overloaded(nullptr); // ok&#xff0c;输出 std::nullptr_t ptr
return 0;
}