软件研发

C ++中的nullptr到底是什么

2020-07-21 13:52:40 | 来源:中培企业IT培训网

对于有经验的C ++和那些了解现代C ++编程语言的人来说,C ++中的nullptr到底是什么,这将是非常简单的问题。但是nullptr不仅是C ++中的编程语言,而且为了解释这一点,我们先了解一下NULL的问题,然后我们将深入研究nullptr的简单实现以及nullptr的一些用例。为什么我们需要nullptr?区分整数0(零)(即NULL)和类型指针的实际null。

nullptr与NULL

NULL为0(零),即将C样式类型转换为void *的整数常数为零,而nullptr是nullptr_t类型的prvalue,该值是整数常量,其值为零。

对于那些相信NULL相同的人,即C和C ++中的(void *)0。想澄清的是,不是:

NULL-cppreference.com (C)

NULL-cppreference.com (C ++)

C ++要求将宏NULL定义为值为0的整数常量表达式。因此与C语言不同,在C ++标准库中不能将NULL定义为(void *)0。

NULL问题

  1.隐式转换

char *str = NULL; // Implicit conversion from void * to char *

int i = NULL; // OK, but `i` is not pointer type

  2.函数调用歧义

void func(int) {}

void func(int*){}

void func(bool){}

func(NULL); // Which one to call?

编译会产生以下错误:

error: call to 'func' is ambiguous

func(NULL);

^~~~

note: candidate function void func(bool){}

^

note: candidate function void func(int*){}

^

note: candidate function void func(int){}

^

1error generated.

compiler exit status 1

3.构造函数重载

struct String

{

String(uint32_t) { /* size of string */ }

String(const char*) { /* string */ }

};

String s1( NULL );

String s2( 5 );

在这种情况下,需要显式转换(即String s((char *)0))。

  简单的nullptr的实现

nullptr是“ 返回类型解析器” 惯用语的一个细微示例, 可以根据要为其分配实例的类型自动推断出正确类型的空指针。

考虑以下最简单且不复杂的nullptr实现:

struct nullptr_t

{

void operator&() const = delete; // Can't take address of nullptr

template

inline operator T*() const { return 0; }

template

inline operator T C::*() const { return 0; }

};

nullptr_t nullptr;

如果上面的代码对您来说似乎很奇怪和怪异(尽管应该不会),那么我建议您阅读我之前有关高级C ++概念的文章。这里的魔术只是模板化转换运算符。

如果您有更权威的资料,那么这里是LLVM header中nullptr的具体实现。

nullptr的用例

struct C { void func(); };

int main(void)

{

int *ptr = nullptr; // OK

void (C::*method_ptr)() = nullptr; // OK

nullptr_t n1, n2;

n1 = n2;

//nullptr_t *null = &n1; // Address can't be taken.

}

如上例所示,当将nullptr分配给整数指针时,将创建模板化转换函数的int类型实例,方法也是如此。

这样,通过利用模板功能,实际上每次创建新类型分配时,我们实际上都在创建适当类型的空指针。

由于nullptr是值为零的整数文字,因此您无法使用通过删除运算符完成的地址。

  1.函数使用nullptr调用清晰度

void func(int) { /* ... */}

void func(int *) { /* ... */}

void func(bool) { /* ... */}

func(nullptr);

现在,func(int *)将被调用,因为nullptr将隐式推导为int *。

  2.在nullptr_t上进行类型转换

将nullptr_t强制转换为整数类型需要reinterpret_cast,并且具有与(void *)0强制转换为整数类型相同的语义。

只要目标类型足够大,就将nullptr_t强制转换为整数类型。考虑一下:

// int ptr_not_ok = reinterpret_cast(nullptr); // Not OK

long ptr_ok = reinterpret_cast(nullptr); // OK

reinterpret_cast无法将nullptr_t转换为任何指针类型。请改用static_cast。

void func(int*) { /*...*/ }

void func(double*) { /*...*/ }

func(nullptr); // compilation error, ambiguous call!

// func(reinterpret_cast(nullptr)); // error: invalid cast from type 'std::nullptr_t' to type 'int*'

func(static_cast(nullptr)); // OK

nullptr可以隐式转换为任何指针类型,因此使用static_cast进行显式转换仅有效。

  3.nullptr_t可比

int *ptr = nullptr;

if (ptr == 0); // OK

if (ptr <= nullptr); // OK

int a = 0;

if (a == nullptr); // error: invalid operands of types 'int' and 'std::nullptr_t' to binary 'operator=='

来自 Wikipedia:-…空指针常量:nullptr。它的类型为nullptr_t,它可以隐式转换,并且可以与任何指针类型或指针到成员类型进行比较。

-除了布尔值,它不能隐式转换或与整数类型媲美。

const int a = 0;

if (a == nullptr); // OK

const int b = 5;

if (b == nullptr); // error: invalid operands of types 'const int' and 'std::nullptr_t' to binary 'operator=='

  4.模板参数的类型为std :: nullptr_t

template

void ptr_func(T *t) {}

ptr_func(nullptr); // Can not deduce T

如前所述,Return Type Resolver需要一个受让人来推断类型。

template

void val_func(T t) {}

val_func(nullptr); // deduces T = nullptr_t

val_func((int*)nullptr); // deduces T = int*, prefer static_cast though

  5.从nullptr_t转换为bool

从cppreference中:

-在直接初始化的上下文中 ,可以从std :: nullptr_t类型的prvalue初始化bool对象 ,包括nullptr。结果值为false。但是,这不被视为隐式转换。

转换仅允许直接初始化,而不允许复制初始化,其中包括按值将参数传递给函数的情况。例如:

bool b1 = nullptr; // Not OK

bool b2 {nullptr}; // OK

void func(bool){}

func(nullptr); // Not OK, need to do func(static_cast(nullptr));

6.杂项

typeid(nullptr); // OK

throw nullptr; // OK

char *ptr = expr ? nullptr : nullptr; // OK

// char *ptr1 = expr ? 0 : nullptr; // Not OK, types are not compatible

static_assert(sizeof(NULL) == sizeof(nullptr_t));

常见问题汇总

  何时引入nullptr?

C ++ 11

  nullptr是关键字还是std :: nullptr_t类型的实例?

true和false都是关键字和文字,因为它们都有一个类型(bool)。nullptr是类型为std :: nullptr_t 的指针文字,它是一个prvalue,即纯 rvalue,您不能使用&来获取它的地址更多。

  使用nullptr有什么优势?

重载集之间没有函数调用歧义。

您可以使用nullptr_t进行模板专业化。

代码将变得更加安全,直观和富有表现力。如果(ptr == nullptr); 而不是if(ptr == 0);。

  C ++中的NULL是否等于C ++ 11中的nullpt?

一点也不。以下行甚至无法编译:

cout<<

  可以将nullptr转换为bool吗?

是,但仅当直接初始化时。即bool is_false {nullptr};。否则需要使用static_cast。

  如何定义nullptr?

它只是被称为Return Type Resolver的模板化转换运算符。

通过上述介绍,C ++中的nullptr到底是什么相信大家已经清楚了吧,如果想了解更多关于C ++的信息,请继续关注中培伟业。

标签: 软件研发