C++11新特性


nullptr替代 NULL

传统C++会把NULL、0视为同一种东西,主要取决于编译器如何定义NULL,有些编译器会将NULL定义为((void*)0),有些则会定义为0。(在C语言中,NULL被定义为(void*)0,而在C++语言中,NULL则被定义为整数)但是在《C++ Primer 5th》这本书中P49提到:NULL是预处理变量,在头文件cstdlib中定义,它的值就是0。

C++不允许直接将 void* 隐式转换为其他类型,但是如果NULL被定义成 ((void*)0),那么当编译char * ch=NULL时,NULL只好被定义成0。从而导致C++中重载混乱
例如:

void f(char* ch);
void f(int);

对于这两个函数来说,如果 NULL 又被定义为了 0 那么 foo(NULL); 这个语句将会去调用 foo(int),从而引发错误。

为了解决这个问题,C++11引入了nullptr关键字,专门来区分空指针,0的问题。

nullptr 的类型为 nullptr_t,能够隐式的转换为任何指针或成员指针的类型,也能和他们进行相等或者不等的比较。

const class nullptr_t{
public:
 template<class T> inline operator T*() const{ return 0; }
 template<class C, class T> inline operator T C::*() const { return 0; }
private:
 void operator&() const;
} nullptr = {};

但是,nullptr同样存在一定的问题
例如:

#include <iostream>


using namespace std;
void fun(char* p)
{
	cout << "char* p" << endl;
}
void fun(int* p)
{
	cout << "int* p" << endl;
}
void fun(int p)
{
	cout << "int p" << endl;
}
int main()
{
	fun((char*)nullptr);//语句1
	fun(nullptr);//语句2
	fun(NULL);//语句3
	return 0;
}

结果:
在这里插入图片描述
出现重载函数调用不明确的错误,主要是由于传入nullptr指针仍然存在无法区分实际调用那个函数

如果将此行注释,则
在这里插入图片描述


类型推导

C++11 引入了 auto 和 decltype 这两个关键字实现了类型推导,让编译器来进行判断变量的类型。

auto

auto 让编译器通过初始值来推算变量的类型。显然,auto定义的变量必须有初始值。

注意

  • 语句中所有变量的初始基本数据类型必须一样
auto sz = 0, pi = 3.14; //错误
  • auto不能用于函数传参
int add(auto x, auto y);//错误
  • auto不能用于推导数组类型
#include <iostream>

int main() {
 	auto i = 5;

 	int arr[10] = {0};
 	auto auto_arr = arr;
 	auto auto_arr2[10] = arr;

 return 0;
}

输出:
在这里插入图片描述

decltype

有的时候我们还会遇到这种情况,我们希望从表达式中推断出要定义变量的类型,但却不想用表达式的值去初始化变量。还有可能是函数的返回类型为某表达式的值类型。在这些时候auto显得就无力了,所以C++11又引入了第二种类型说明符decltype,它的作用是选择并返回操作数的数据类型。在此过程中,编译器只是分析表达式并得到它的类型,却不进行实际的计算表达式的值。

decltype 关键字是为了解决 auto 关键字只能对变量进行类型推导的缺陷而出现的。


区间迭代

基于范围for循环

最常用的 std::vector 遍历将从:

std::vector<int> arr(5, 100);
for(std::vector<int>::iterator i = arr.begin(); i != arr.end(); ++i) {
    std::cout << *i << std::endl;
}

变成:

// & 启用了引用
for(auto &i : arr) {    
    std::cout << i << std::endl;
}

初始化列表

C++11 提供了统一的语法来初始化任意的对象,例如:

struct A {
    int a;
    float b;
};
struct B {

    B(int _a, float _b): a(_a), b(_b) {}
private:
    int a;
    float b;
};

A a {1, 1.1};    // 统一的初始化语法
B b {2, 2.2};

Lambda表达式

Lambda 表达式,实际上就是提供了一个类似匿名函数的特性,而匿名函数则是在需要一个函数,但是又不想费力去命名一个函数的情况下去使用的。

Lambda 表达式的基本语法如下:

[ caputrue ] ( params ) opt -> ret { body; };
  1. capture是捕获列表;
  2. params是参数表;(选填)
  3. opt是函数选项;可以填mutable,exception,attribute(选填)
    mutable说明lambda表达式体内的代码可以修改被捕获的变量,并且可以访问被捕获的对象的non-const方法。
    exception说明lambda表达式是否抛出异常以及何种异常。
    attribute用来声明属性。
  4. ret是返回值类型(拖尾返回类型)。(选填)
  5. body是函数体。

新增容器

std::forward_list

std::forward_list 是一个列表容器,使用方法和 std::list 基本类似。
和 std::list 的双向链表的实现不同,std::forward_list 使用单向链表进行实现,提供了 O(1) 复杂度的元素插入,不支持快速随机访问(这也是链表的特点),也是标准库容器中唯一一个不提供 size() 方法的容器。当不需要双向迭代时,具有比 std::list 更高的空间利用率。

右值引用和move

理解不到位,后续再更新吧

学习过程中,主要参考了jiange_zh的文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值