c++11中nullptr(与NULL的区别)

首先呢,要明白一点儿,NULL是一个无类型的东西,而且是一个宏。而宏这个东西,从C++诞生开始,就是C++之父嗤之以鼻的东西,他推崇尽量避免宏。而在他的FAQ中,也有相应的一个关于NULL与0的解释,也谈到了这一点儿。Stroustrup: C++ Style and Technique 

在C++标准中,我们可以见到一个词语叫做null pointer constant,其实在C++11标准前,是只承认0为null pointer constant的。所以,在C++中,我们也经常能听到一个说法,就是赋予null pointer,应该是使用0,而非NULL。而nullptr pointer constant这个词语在C++11发布后,终于再添了一个成员,就是nullptr。而与NULL本质不同的是,nullptr是有类型的(放了在stddef头文件中),类型是 typdef decltype(nullptr) nullptr_t; 而正是因为是有类型的,这给我们编译器实现nullptr的时候带来了更多细节的考虑,当然也给了使用者更多的保障,所以如果你的编译器支持nullptr,请一定使用nullptr!

而nullptr的出现背景,其实是很简单的,C++哲学上来说就是C++之父一直对null pointer没有一个正式的表示感到非常不满,而更工程的来说,就是关于重载这个问题。

void f(void*)
{
}

void f(int)
{
}

int main()
{
f(0); // what function will be called?
}

而引入了nullptr,这个问题就得到了真正解决,会很顺利的调到void f(void*)这个版本。

好了,真的以为nullptr就这样了么? 我前面说过了nullptr是有类型的,叫做nullptr_t,这给我们编译器实现带来了诸多要考虑的东西,不幸的话让我们来举点儿奇葩例子吧!

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。

而nullptr有类型后,还能做什么呢?那当然就是可以捕获异常了。

int main()
{
try
{
throw nullptr;
}
catch(nullptr_t)
{

}
}
你扔一个NULL试试?看他应该用什么收,正是因为没有类型,所以就要用它的本质类型,比如long什么的来说。你扔一个0试试?那就也不是所谓的空指针类型了,就是要用int什么的来收了。

所以,推崇nullptr是有道理的,我们在编译器实现nullptr的时候考虑了非常非常多的细节,还有很多你们可能一直用不到的情况,我们都要用来测试,目的就是保障开发者的使用。再次那句话,如果你的编译器支持nullptr,请一定使用nullptr!


1、为什要有nullptr

      我们给一个指针赋初值的时候一般这么写  FILE* fp = NULL;
      这里有个NULL的定义,一般情况下它是这么定义的:
     
[cpp]  
#ifdef __cplusplus  
#define NULL    0  
#else  
#define NULL    ((void *)0)  
#endif  
 
      在c语言环境下,由于不存在函数重载等问题,直接将NULL定义为一个void*的指针就可以完美的解决一切问题。
      但是在c++环境下情况就变得复杂起来, 首先我们不能写这样的代码   FILE* fp = (void*)0;   将void*直接赋值给一个指针是不合法的,编译器会报错。 我们只能这样写代码
[cpp]  
FILE* fp = (FILE*)0;  
// or  
FILE* fp = 0;  
 
  所以在c++下面,NULL就被直接定义为一个整型 0。  在大多数情况下这并不会产生什么问题,但是万一有重载或者模板推导的时候,编译器就无法给出正确结果了。比如下面的情形:
[cpp]  
void call_back_process(CCObject* target, void* data);  
bind(call_back_process, target, NULL);   // error 函数类型是void* ,但是我们绑定的是一个整型 0  
2、 nullptr的应用场景:
       如果我们的编译器是支持nullptr的话,那么我们应该直接使用nullptr来替代NULL的宏定义。正常使用过程中他们是完全等价的。
3、模拟nullptr的实现:
      某些编译器不支持c++11的新关键字nullptr,我们也可以模拟实现一个nullptr
[cpp]  www.2cto.com
const  
class nullptr_t_t  
{  
public:  
    template<class T>           operator T*() const {return 0;}  
    template<class C, class T>  operator T C::*() const { return 0; }  
private:  
    void operator& () const;  
} nullptr_t = {};  
#undef NULL  
#define NULL nullptr_t   





  • 8
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值