目录括号内为适合人群,所有库作者的内容暂不做学习,可自行查阅《深入理解C++11:C++11新特性解析与应用》。网盘链接: https://pan.baidu.com/s/1Jf29R7-foOoXJ5UW3mTKVA 密码: 7vgq
目录
1.强类型枚举(部分人)
2.堆内存管理:智能指针与垃圾回收(类,库作者)
①显式内存管理
②C++11的智能指针
③垃圾回收的分类
④C++与垃圾回收
⑤C++11与最小垃圾回收支持
⑥垃圾回收的兼容性
1.强类型枚举 ^
C++11标准中,引入了一种新的枚举类型,即“枚举类”,又称“强类型枚举”。声明强类型枚举只需要在enum后加上关键字class,如:
enum class Color { Red,Blue,Green,Yellow };
强类型枚举具有以下几点优势:
enum class Color :char { Red, Blue, Green, Yellow };
普通枚举类型与强枚举类型比较的例子:
enum Color1 { Red1, Blue1, Green1, Yellow1 }; //普通的枚举类型
enum class Color2 { Red2, Blue2, Green2, Yellow2 };//强枚举类型
int main()
{
//普通枚举成员可以直接调用
cout << Red1 << " " << Blue1 << " " << Green1 << " " << Yellow1 << endl;
//强枚举成员则需要枚举名::成员名,且不能被cout输出
//cout<<Color::Red2<<" " << Color::Blue2 << " " << Color::Green2<< " " << Color::Yellow2 << endl;
Color1 c1 = Red1;
c1 = Blue1;
Color2 c2 = Color2::Red2;
//不能通过编译
//c2 = Blue2;
if (c1 == Red1)
cout << "红1" << endl;
if (c2 == Color2::Red2)
cout << "红2" << endl;
//普通枚举可以直接和整型进行比较
if (c1 >= 0)
cout << "大于等于0" << endl;
//强枚举不能直接与整型比较,因为不会隐式转换成整型,需要显式转换
//if (c2 >= 0)
//cout << "大于等于0" << endl;
if ((int)c2 >= 0)
cout << "大于等于0" << endl;
cout << is_pod<Color1>::value << endl; //输出:1,是POD类型
cout << is_pod<Color2>::value << endl; //输出:1,是POD类型
}
为了配合强类型枚举,C++11对原有枚举类型进行了扩展,使其也可以像强类型枚举一样,显式地指定成员类型,如:
enum Color1 :char{ Red1, Blue1, Green1, Yellow1 };
第二个扩展则是作用域,即:
enum Color1 :char{ Red1, Blue1, Green1, Yellow1 };
int main()
{
Color1 c1 = Red1; //在父作用域里
c1 = Color1::Blue1; //在枚举类型自己定义的作用域里
}
注:匿名的enum class,因为其实强类型作用域的,所以匿名的enum class可能啥都做不了,通常使用强类型枚举都应该为其提供一个名字。
2.堆内存管理:智能指针与垃圾回收 ^
①显式内存管理 ^
我们在处理现实生活中的C/C++程序的时候,常会遇到诸如程序运行时突然退出,或占用的内存越来越多,这些问题的源头都跟C/C++中的显式堆内存管理有关。通常有以下几种情况:
为了应对这些问题,C++中提供了智能指针,在C++11标准中,智能指针被进行了改进,以更加适应实际的应用需求。而进一步,标准库还提供了所谓“最小垃圾回收”的支持。
②C++11的智能指针 ^
在C++98中,智能指针通过一个模板类型“auto_ptr”来实现,但由于有一些缺点(拷贝时返回一个左值,不能调用delete []等),在C++11标准中被废弃了,改用unique_ptr,shared_ptr和weak_ptr等智能指针来自动回收堆分配的对象。C++11中使用新的智能指针的简单例子如下:
int main()
{
unique_ptr<int> p1(new int(11));
//unique_ptr<int> p2(p1); //不能通过编译
cout<<*p1<<endl; //输出:11
unique_ptr<int> p3(move(p1)); //现在p3是数据唯一的unique_ptr智能指针
cout<<*p3<<endl; //输出:11
//cout<<*p1<<endl; //运行时错误
p3.reset(); //显式释放内存
p1.reset(); //p1已经不指向任何数据,但不会导致运行时错误
//cout<<*p3<<endl; //运行时错误
shared_ptr<int> pp1(new int(22));
shared_ptr<int> pp2=pp1;
cout<<*pp1<<endl; //输出:22
cout<<*pp2<<endl; //输出:22
pp1.reset();
cout<<*pp2<<endl; //输出:22
}
除了以上两种智能指针,C++11标准中还有weak_ptr。weak_ptr可以指向shared_ptr指针指向的对象内存,却并不拥有该内存。使用weak_ptr成员lock,可以返回其指向内存的一个shared_ptr对象,且在所指对象内存已经无效时,返回指针空值。这在验证shared_ptr智能指针的有效性上会有很大作用。如下:
int main()
{
shared_ptr<int> pp1(new int(22));
shared_ptr<int> pp2 = pp1;
weak_ptr<int> ppp = pp1;
cout << *pp1 << endl; //输出:22
cout << *pp2 << endl; //输出:22
pp1.reset();
if (ppp.lock() == nullptr)
cout << "指针为空1" << endl; //shared_ptr对象还在,不输出
cout << *pp2 << endl; //输出:22
pp2.reset();
if (ppp.lock() == nullptr)
cout << "指针为空2" << endl; //shared_ptr对象内存被释放,输出
}
③垃圾回收的分类 ^
”垃圾“,即我们之前使用过,现在不再使用或者没有任何指针再指向的内存空间。而将这些“垃圾”收集起来以便再次利用的机制,被称为”垃圾回收“。垃圾回收的方式很多,主要分为两大类:
①基于引用计数的垃圾回收器
引用计数主要是使用系统记录对象被引用的次数。当对象被引用的次数变为0时,该对象即可被视作“垃圾”而回收。优点:该方法不会造成程序暂停,也不会对系统的缓存或者交换空间造成冲击。缺点:比较难处理“环形引用”问题,此外由于计数带来的额外开销也并不小,所以在实用上也有一定的限制。
②基于跟踪处理的垃圾回收器
相比于引用计数,跟踪处理的垃圾回收机制被更广泛地应用。其基本方法是产生追踪对象的关系图,然后进行垃圾回收。使用跟踪方式的垃圾回收算法主要有以下几种:
④C++与垃圾回收 ^
指针的灵活使用可能是C/C++中的一大优势,而对于垃圾回收来说,却会带来很大的困扰。如下:
int main()
{
int *p = new int;
p += 10; //移动指针,可能导致垃圾回收器
p -= 10; //回收原来指向的内存
*p = 10; //再次使用原本相同的指针则可能无效
}
⑤C++11与最小垃圾回收支持 ^
C++11新标准为了做到最小的垃圾回收支持,首先对“安全”的指针进行了定义,即安全派生的指针。安全派生的指针是指向由new分配的对象或其子对象的指针。安全派生指针的操作包括:
①在解引用基础上的引用,如:&*p。
②定义明确的指针操作,如:p+1。
③定义明确的指针转换,如:static_cast<void*>(p)。
④指针和整型之间的reinterpret_cast,如:reinterpret_cast<intptr_t>(p)
注:intptr_t是C++11中一个可选择实现的类型,其长度等于平台上指针的长度(通过decltype声明)
在C++11的标准中,最小垃圾回收支持是基于安全派生指针这个概念的。我们可以用过get_pointer_safety函数查询来确认编译器是否支持这个特性。其返回一个pointer_safety类型的值,如果该值为pointer_safety::strict,则表明编译器支持最小垃圾回收及安全派生指针等相关概念,如果该值为pointer_safety::relax或pointer_safety::preferred,则表明编译器不支持。
如果代码中出现了指针不安全使用的状况,C++11允许我们通过一些API来通知垃圾回收器回收该内存,即declare_reachable函数和函数模板undeclare_reachable。declare_reachable()显示地通知垃圾回收器某一个对象应被认为可到达(垃圾回收的术语),而undeclare_reachable()则是取消这种可达声明。
⑥垃圾回收的兼容性 ^
尽管在设计C++11标准时想尽可能保证向后兼容,但对于垃圾回收来说,破坏向后兼容是不可避免的。想让老的代码毫不费力地使用垃圾回收,现实情况下对大多数代码是不可能的。
C++11标准中对指针的垃圾回收支持仅限于系统提供的new操作符分配的内存,而malloc分配的内存则会被认为总是可达的,即无论何时垃圾回收器都不予回收。