C++11中0与 NULL与nullptr之间的关系

1.从本质上
 1) 0是int型的字面值常量
 2) NULL 是预处理变量,定义在 cstdlib 中,其值是0
 3) nullptr 是 nullptr_t 类型的字面值。
2.cstdlib 中 NULL 的定义
  #ifdef __cplusplus
  #define NULL 0
  #else
  #define NULL ((void *)0)
  #endif
之所以这样定义的原因,是因为在C语言中,允许 void* 类型隐式转换为任意指针类型,而C++中不允许这样的强制类型转换,但是可以为任意类型的指针赋0值,因此,在C++中将NULL 定义为0.
3.0 比 NULL 好
在网上的资料中,均是一致认为 0 比 NULL 好,因为很多可能会出错的时候,使用 0 更直观,如:
void test(int i){ cout << "in int" << endl; }
void test(int * i){ cout << "in int *" << endl; }
int main()
{
    test(0); //输出 in int
    test(NULL); //输出 in int
}
此时,两个函数调用均会调用参数为 int 的 test,使用 0 调动的版本看起来更加直观,因为 0 本身是一个 int 类型的字面值常量,而会潜意识的认为 NULL 应该是一个指针类型,不利于查错
4.nullptr 比 0 更好
nullptr 是 nullptr_t 类型的常量,而该类型定义了转到任意指针类型的转换操作符,同时不允许该类型的对象转换到非指针类型,在上面的调用例子中,使用 nullptr,将会调用第二个函数,输出 “in int*”,因为 nullptr被转换为了int * ,符合我们通常的理解。对于nullptr_t 的类型可以定义如下:
5.nullptr_t实现
class nullptr_t
{
public:
	template
	inline operator T*() const //定义类型转换操作符,使nullptr_t 可转为任意非类成员指针类型
	{ 
          return 0;
        }
	//重载类型转换操作符,使 nullptr_t 可以转换为类 C 中任意的指针类型(数据成员指针/函数成员指针)	
	//对类中数据成员的指针,T 将被推导为数据成员的类型 eg: int (X::*); 此时 T 为 int,C 为 X
	//对类中函数成员的指针,T 将被推导为函数成员的类型 eg: int (X::*)(int); 此时T 等效于: typedef int (T)(int)
	template
	inline operator T C::*() const  
	{ return 0; } 			
private:				
	void operator&() const;
};
const null_ptr nullptr = {}

6.nullptr如何使用
nullptr关键字用于标识空指针,是std::nullptr_t类型的(constexpr)变量。它可以转换成任何指针类型和bool布尔类型(主要是为了兼容普通指针可以作为条件判断语句的写法),但是不能被转换为整数。
char *p1 = nullptr;     // 正确
int  *p2 = nullptr;     // 正确
bool b = nullptr;       // 正确. if(b)判断为false
int a = nullptr;        // error

7.测试nullptr
union U
{
    long i;
    nullptr_t t;
};

int main()
{
    U u;
    u.i = 3;
    printf("%ld\n",(long)u.t); // What it is? 0 or 3?
}
那么这是应该符合union语意还是nullptr的语意呢?这在标准中是没有说的,我们也为此争论了非常久。当然在我们编译器的实现还是保持了nullptr的语意,结果是0。

你可能感兴趣的:(C++学习)