C++ 2.0新特性——关键字(nullptr、override、enum class)

C++ 2.0新特性——关键字

一、nullptr

nullptr不具备整型类型,实际类型为nullptr_t,可以隐式转化为所有的裸指针类型

void f(int);
void f(bool);
void f(void*)

f(0):调用f(int),而不是f(void*);
f(null):可能编译无法通过,一般调用f(int)。不会调用f(void*)。
f(nullptr):调用f(void*)

1、相较于0或NULL,优先使用nullptr
2、避免了在整型和指针之间重载,很好地区分了整型0和指针类型nullptr

二、别名声明——using

优先使用using而非typedef:
1、typedef不支持模板化,而别名声明(using)支持。

template<typename T>
using MyAllocList = list<T, MyAlloc<T>>;
MyAllocList<Widget> lw;


template<typename T>
struct  MyAllocList
{
	typedef list<T, MyAlloc<T>> type;
};
MyAllocList<Widget>::type lw;

2、可以让人免写"::type"后缀,并且在模板内,对于内嵌typedef的引用经常加上typename前缀

class Widget{
	typename MyAllocList<T>::type list;
};

MyAllocList::type list代表一个依赖模板类型形参的类型,称为依赖类型,需要加typename前缀,使用别名声明,则MyAllocList list即可。

三、限定作用域枚举enum class

优先使用限定作用域枚举类型,而非不限作用域的枚举类型。
优点:
1、限定作用域的枚举类型仅在枚举类型内部可见。只能通过强制类型转换至其他类型。好处:
(1)、限定作用域的枚举类型带来的名字空间污染降低。

enum Color { black, white, red };
auto white = false;//错误。white和Color的作用域相同,已经被声明过了

enum class Color { black, white, red };
auto white = false;//正确,范围内无white
Color c = white;//错误,范围内无white
Color c = Color::white;//正确

(2)、enum class的枚举量是强类型的,不存在隐式转换类型。只能通过强制类型转换static_cast。而enum允许隐式转换的。
(3)、可以进行前置声明

enum Color;//错误
enum class Color;//正确

2、限定作用域的枚举类型和不限范围的枚举类型都支持底层类型指定。enum class底层类型分别为int,enum没有默认的底层类型。

enum class Status;//底层类型为int

enum class Status: double//指定类型为double

3、enum class总是可以进行前置声明,而enum只有在指定了默认底层类型的前提下进行前置声明。

四、删除函数=delete

优先使用删除函数,而非private未定义函数。删除系统自动生成的默认构造函数、拷贝构造函数等。任何函数都可以删除,包括非成员函数和模板具现。

五、改写函数override

改写函数的条件:
1、基类中的函数必须是虚函数
2、基类和派生类中的函数名必须完全相同
3、基类和派生类中的函数形参类型必须完全相同
4、基类和派生类中的函数常量性必须完全相同
5、基类和派生类中的函数返回值和异常规格必须兼容
6、基类和派生类中的函数引用饰词必须完全相同

class Widget{
	void do() &;//仅在*this为左值时调用
	void do() &&;//仅在*this为右值时调用
};

改写函数时,在函数后加override,能保证在编译时检查改写的要求是否满足。

六、常量迭代器——const_iterator

任何时候只要需要一个迭代器,其指代的内容不需要修改,则使用const_iterator。此时容器中的cbegin() cend()都返回const_iterator

vector<int> values;
auto it = find(values.cbegin(), values.cend(), 1);
...
values.insert(it, 2);

注:C++11中仅添加了非成员函数版本的begin和end,而没有添加cbegin(),cend(),rbegin() ,rend()、crbegin()、crend()。C++14都添加了。
在设计通用代码时,优先使用非成员函数版本的begin()、end()等,而非成员函数。

七、函数异常——noexcept

只要函数不会发射异常,就在函数后加上noexcept声明。
1、noexcept声明是函数接口的组成部分,这意味着调用方式可能会对它有依赖。当明知一个函数不会发射异常而不加上noexcept声明,这就是接口规格缺陷,类似于函数加const;同时让编译器生成更好的目标代码。

加上noexcept声明,使得优化器不需要在异常传出函数的前提下,将执行期栈保持在开解状态;也不需要在异常溢出函数的前提下,保证所有其中的对象以其被构造顺序的逆序完成析构。有更多机会得到优化

2、noexcept性质对于移动操作、swap、函数释放函数和函数析构最有价值。

3、大部分函数都是异常中立的:自身不抛出异常,但他们的调用函数可能发射异常,不具备noexcept性质。

4、一般把nonexcept的声明保留给那些带有“宽松契约”的函数上。
**宽松契约:**无前置条件,调用此函数无需关注程序状态,传入的实参也无限制。

八、常量——constexpr

只要有可能使用constexpr,就使用它。

1、所有constexpr对象都是const对象,并非所有的const对象都是constexpr对象,constexpr由编译期已知的值完成初始化。

	int s = 0;   //非constexpr变量
	constexpr auto arraySize1 = s;//报错,s的值在编译期未知。会显示s的值不可用做常量。
	array<int, s> data1;//错误,同上
	constexpr auto arraySize2 = 10;//正确,10是个编译期常量
	array<int, arraySize2> data2;//正确

换作const:

	int s = 0;
	const auto arraySize = s;//正确,arraySize是s的一个const副本
	array<int, arraySize> data;//错误,arraySize的值非编译期未知,会显示arraySize的值不可用做常量。

2、constexpr函数在调用时,若传入的实参值是编译期已知的,则会产生编译期结果;若传入的一个或多个在编译期未知,则在运行期执行结果计算,和普通函数无异。

constexpr int pow(int base,int exp) noexcept{}

constexpr并不表明pow要返回一个const值,而是表明若base和exp均为编译期常量,则pow返回结果可以当做一个编译期常量使用;若有一个不是编译期常量,则pow返回的结果就是在执行期计算

3、constexpr对象或者函数能够应用在作用域更广的语境中。

九、const函数的线程安全性——互斥量和原子操作

在多线程中,线程中的一个或多个可能企图修改数据成员,导致有多个不同的线程在没有同步的情况下读写同一块内存,造成“数据竞争”。此时可以使用互斥量mutex加锁

mutable mutex m;
void f() const{
	lock_guard<mutex> g(m);//加互斥量,加锁
	..
}//解锁

对于单个要求同步的变量或内存区域,使用atomic就足够了;但是若有两个或多个变量或内存区域作为一整个单位进行操作,就要使用互斥量。

mutable atomic<unsigned> count{0};
void f() const noexcept{
	++count;//带原子性自增
	..
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dailingGuo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值