一. nullptr与nullptr_t

(一)nullptr_t是一种数据类型,而nullptr是该类型的一个实例。通常情况下,也可以通过nullptr_t类型创建另一个新的实例。

(二)所有定义为nullptr_t类型的数据都是等价的,行为也是完全一致的。

(三)std::nullptr_t类型,并不是指针类型,但可以隐式转换成任意一个指针类型(注意不能转换为非指针类型,强转也不行)。

(四)nullptr_t类型的数据不适用于算术运算表达式。但可以用于关系运算表达式(仅能与nullptr_t类型数据或指针类型数据进行比较,当且仅当关系运算符为==、<=、>=等时)

【编程实验】nullptr与nullptr_t的关系

#include <iostream>
#include <vector>
#include <iomanip> //for setbase;
#include <boost/type_index.hpp> using namespace std;
using boost::typeindex::type_id_with_cvr; //辅助类模板,用于打印T的类型
template <typename T>
void printType(string s)
{
cout << s << " = " << type_id_with_cvr<T>().pretty_name() << endl;
} //4. 用于测试nullptr并不是指针类型
template<typename T>
void func_ptr(T* t) {} template<typename T>
void func_value(T t) {} int main()
{
//1. 查看nullptr的类型
printType<decltype(nullptr)>("nullptr的类型: "); //std::nullptr_t
cout << "sizeof(nullptr) = " << sizeof(nullptr) << endl; //2. nullptr可以隐式转换为任何指针!
void* vptr = nullptr;
char* cptr = nullptr; //3. 使用关系运算符进行比较nullptr与nullptr_t类型的变量
//3.1 nullptr支持关系运算
nullptr_t my_nullptr = nullptr; //通过nullptr_t定义新的实例(vc下必须初始化,但g++默认下己初始化为nullptr) (nullptr == my_nullptr) ? (cout << "newptr == nullptr" << endl) : (cout << "newptr != nullptr" << endl);
(nullptr < my_nullptr) ? (cout << "newptr < nullptr" << endl) : (cout << "newptr !< nullptr" << endl); //3.2 nullptr不支持算术运算
//nullptr += 1; //nullptr是个常量
//nullptr * 5; //4. nullptr_t并不是指针类型(尽管看起来、用起来都像指针类型)
func_ptr((float*)nullptr); //ok, T = float。nullptr可以转为任意类型的指针
//func_ptr(nullptr); //编译失败,nullptr的类型是nullptr_t,而不是指针类型
//编译器并不会“智能”地推导成某种类型的指针(含void*) func_value(); // T = int;
func_value(nullptr); //T = nullptr_t;
func_value((float*)nullptr); //T = float* return ;
}
/*输出结果
nullptr的类型: = std::nullptr_t
sizeof(nullptr) = 4
newptr == nullptr
newptr !< nullptr
*/

二、nullptr与NULL

(一)nullptr与NULL的区别

  1. NULL是一个宏定义,C++中通常将其定义为0编译器总是优先把它当作一个整型常量(C标准下定义为(void*)0)。

  2. nullptr是一个编译期常量,其类型为nullptr_t它既不是整型类型,也不是指针类型

  3. 在模板推导中,nullptr被推导为nullptr_t类型,仍可隐式转为指针。但0或NULL则会被推导为整型类型

  4.要避免在整型和指针间进行函数重载。因为NULL会被匹配到整型形参版本的函数,而不是预期的指针版本。

(二)nullptr与(void*)0的区别

  1. nullptr到任何指针的转换是隐式的。(尽管nullptr不是指针类型,但仍可当指针使用)

  2.(void*)0只是一个强制转换表达式,其返回void*指针类型,只能经过类型转换到其他指针才能用

【编程实验】nullptr与NULL的区别

#include <iostream>
#include<memory>
#include <mutex>
#include <iomanip> //for setbase;
using namespace std; //3. 避免整型和指针间的重载
void f(int)
{
cout <<"invoke f(int)" << endl;
} void f(void*)
{
cout << "invoke f(void*)" << endl;
} //4. nullptr在模板中的表现
class Widget{};
int f1(std::shared_ptr<Widget> spw) { return ; }
double f2(std::unique_ptr<Widget> upw) { return ; }
bool f3(Widget* pw) { return true; }
using MuxGuard = std::lock_guard<std::mutex>; template<typename Func, typename Mux, typename Ptr>
decltype(auto) lockAndCall(Func func, Mux& mux, Ptr ptr) //C++14
{
MuxGuard guard(mux);
return func(ptr);
} int main()
{
//1. nullptr是一个右值常量
nullptr_t my_nullptr; cout <<"&my_nullptr = "<< setbase() << &my_nullptr << endl; //nullptr_t类型的对象取地址
//cout << setbase(16) << &nullptr<< endl; //nullptr是个右值常量,不能取地址。
const nullptr_t&& def_nullptr = nullptr; //nullptr是个右值常量,可用右值引用来接。
cout << "&def_nullptr = " << setbase() << &def_nullptr << endl; //可对右值引用取地址(具名变量,本身是左值) //2. nullptr与(void*)0的区别
void* px = NULL;
//int* py = (void*)0; //编译错误,不能隐式将void*转为int*类型
int* pz = (int*)px; //void*不能隐式转为int*,必须强制转换! int* pi = nullptr; //ok!nullptr可以隐式转为任何其他指针类型
void* pv = nullptr; //ok! nullptr可以隐式转为任何其他指针类型 //3. 避免在整型和指针间重载函数
f(); //invoke f(int)
f(NULL); //invoke f(int)
f((char*)); //invoke f(void*)
f(nullptr); //invoke f(void*) //4. nullptr的模板推导中,仍可当指针用。
std::mutex m1, m2, m3;
//auto result1 = lockAndCall(f1, m1, 0); //0被推导为int类型,与share_ptr<Widget>类型不匹配
//auto result2 = lockAndCall(f2, m2, NULL); //同上,NULL被优先当作整型
auto result3 = lockAndCall(f3, m3, nullptr);//nullptr被推导为nullptr_t,但该类可以隐式转为Widget* return ;
}
/*输出结果
&my_nullptr = 00DEFB28
&def_nullptr = 00DEFB10
invoke f(int)
invoke f(int)
invoke f(void*)
invoke f(void*)
*/

第6课 nullptr_t和nullptr的更多相关文章

  1. [c++] Templates

    Template是编译时多态.所有的模板都是在编译时产生对应的代码,它没有面向对象中的虚表,无法实现动态多态. Function Template A function template is a p ...

  2. C++11特性:decltype关键字

    decltype简介 我们之前使用的typeid运算符来查询一个变量的类型,这种类型查询在运行时进行.RTTI机制为每一个类型产生一个type_info类型的数据,而typeid查询返回的变量相应ty ...

  3. C++11---nullptr

    1.nullprt与NULL 代码: void f(int i) {    cout << "f(int)" << endl;} void f(char* ...

  4. 深入理解C++11【5】

    [深入理解C++11[5]] 1.原子操作与C++11原子类型 C++98 中的原子操作.mutex.pthread: #include<pthread.h> #include <i ...

  5. C++11 类型推导decltype

    我们之前使用的typeid运算符来查询一个变量的类型,这种类型查询在运行时进行.RTTI机制为每一个类型产生一个type_info类型的数据,而typeid查询返回的变量相应type_info数据,通 ...

  6. decltype类型声明- 现代C++新特性总结

    decltype类型声明 有时会遇到这样的情况:希望从表达式的类型推断出要定义的变量的类型,但不想用该表达式的值去初始化变量.为了满足这一需求,C++11引入了decltype,它的作用是选择并返回操 ...

  7. C++11——引入的新关键字

    1.auto auto是旧关键字,在C++11之前,auto用来声明自动变量,表明变量存储在栈,很少使用.在C++11中被赋予了新的含义和作用,用于类型推断. auto关键字主要有两种用途:一是在变量 ...

  8. C++11/14笔记

    目录 语言层面 模板表达式中的空格 nullptr和std::nullptr_t 自动推导类型----auto 一致性初始化----Uniform Initialization 初始化列表(initi ...

  9. c++11 指针空值

    1. 引入nullptr的必要性: 典型的指针初始化是将其指向一个空的位置.比如: int* my_ptr = 0; int* my_ptr = NULL; 一般情况下,NULL是一个宏定义. #un ...

随机推荐

  1. CMake的含义和用法解读

    什么是 CMake 你或许听过好几种 Make 工具,例如 GNU Make ,QT 的 qmake ,微软的 MS nmake,BSD Make(pmake),Makepp,等等.这些 Make 工 ...

  2. 有趣的css图形实现

    css通过 border .border-radius .transform,实现各种图形. <!DOCTYPE html> <html lang="en"> ...

  3. loadrunner:Action.c(4): Error -27796: Failed to connect to server "10.8.251.101:10086": [10060] Connection timed out

    Action.c(4): Error -27796: Failed to connect to server "10.8.251.101:10086": [10060] Conne ...

  4. 面试官:你知道Spring中有哪些可以让我们扩展的地方么

    大家都知道我这段时间陆续更新了Spring系列源码分析以及各种扩展点的文章,到了今天可以总算可以更新这篇文章了 首先列举一下一个经典的面试题:Spring中Bean的生命周期: 开始初始化容器 加载B ...

  5. vue多个路由使用同一个页面,通过name判断参数,渲染页面数据

    项目中,发现有多个页面的数据内容相同,只是请求数据的参数不同,就可以使用同一个组件来渲染 这里的客户列表 / 我负责的 / 我参与的 都使用同一个组件,不同点在请求数据的参数 可以看到,通过钩子函数, ...

  6. GeoIP的使用-C语言版

    0x00. 简介 GeoIP库可以根据IP地址(支持IPv4 和 IPv6), 定位该IP所在的 洲.经纬度.国家.省市.ASN 等信息. GeoIP目前已经升级到GeoIP2,GeoIP2有两个版本 ...

  7. AB PLC简述

    一.  PLC基础概念 PLC:可编程序控制器是一种数字运算的电子系统,专为在工业环境下应用而设计.采用可编程的存储器,用来在内部存储执行逻辑运算.顺序控制.定时.计算和算术运算等操作的指令,并通过数 ...

  8. 综合架构之Rsync备份服务,服务端和客户端配置

    服务端配置(即备份服务器) ps:客户端配置见下方 配置一个新服务的步骤: 第一步:先将该服务下载 yum install -y rsync 第二步:编写服务配置文件 配置文件:/etc/rsyncd ...

  9. AMD Ryzen一代、二代CPU一览表

    Ryzen一代(14纳米).二代(12纳米)CPU一览表 http://img30.360buyimg.com/sku/jfs/t1/1134/23/12713/382299/5bd910f9E63b ...

  10. vue-loader作用

    (1)浏览器本身并不认为.vue文件,所以必须对.vue文件进行加载解析,此时需要vue-loader (2)类似的loader还有许多,如:html-loader.css-loader.style- ...