C++11常用知识
Posted Arrow
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++11常用知识相关的知识,希望对你有一定的参考价值。
C++11常用知识
1. 简介
2. C++的结构体和C++类的区别
- 概念:
- class和struct的语法基本相同,从声明到使用,都很相似,但是struct的约束要比class多,理论上,struct能做到的class都能做到,但class能做到的stuct却不一定做的到
- C++结构体的继承默认是public,而c++类的继承默认是private
- class还可以用于表示模板类型,struct则不行
- 类型:struct是值类型,class是引用类型,因此它们具有所有值类型和引用类型之间的差异
- 效率:由于堆栈的执行效率要比堆的执行效率高,但是堆栈资源却很有限,不适合处理逻辑复杂的大对象,因此struct常用来处理作为基类型对待的小对象,而class来处理某个商业逻辑
- 关系:struct不仅能继承也能被继承 ,而且可以实现接口,不过Class可以完全扩展。内部结构有区别,struct只能添加带参的构造函数,不能使用abstract和protected等修饰符,不能初始化实例字段
- 性能:关于 Class性能好还是Struct性能好(换言堆性能好?还是栈性能好?) 那么什么时机该用呢 ,比较struct和 class的不同,以下总结可以参考一下:
- 在表示诸如点、矩形等主要用来存储数据的轻量级对象时,首选struct。
- 在表示数据量大、逻辑复杂的大对象时,首选class
- 在表现抽象和多级别的对象层次时,class是最佳选择
3. 智能指针
- 为什么引入智能指针
- 在实际的 C++ 开发中,我们经常会遇到诸如程序运行中突然崩溃、程序运行所用内存越来越多最终不得不重启等问题,这些问题往往都是内存资源管理不当造成的。比如:
- 有些内存资源已经被释放,但指向它的指针并没有改变指向(成为了野指针),并且后续还在使用;
- 有些内存资源已经被释放,后期又试图再释放一次(重复释放同一块内存会导致程序运行崩溃);
- 没有及时释放不再使用的内存资源,造成内存泄漏,程序占用的内存资源越来越多。
- 什么是智能指针
- 所谓智能指针,可以从字面上理解为“智能”的指针
- 具体来讲,智能指针和普通指针的用法是相似的,不同之处在于,智能指针可以在适当时机自动释放分配的内存
- 也就是说,使用智能指针可以很好地避免“忘记释放内存而导致内存泄漏”问题出现
3.1 C++11 std::shared_ptr智能指针
- 与其它智能指针的区别
- 与unique_ptr、weak_ptr 不同之处在于,多个 shared_ptr 智能指针可以共同使用同一块堆内存。并且,由于该类型智能指针在实现上采用的是引用计数机制,即便有一个 shared_ptr 指针放弃了堆内存的“使用权”(引用计数减 1),也不会影响其他指向同一堆内存的 shared_ptr 指针(只有引用计数为 0 时,堆内存才会被自动释放)
3.1.1 std::shared_ptr智能指针的创建
- 构造出std::shared_ptr 类型的空智能指针
std::shared_ptr<int> p1; //不传入任何实参
std::shared_ptr<int> p2(nullptr); //传入空指针 nullptr
- 注意,空的 shared_ptr 指针,其初始引用计数为 0,而不是 1
- 构造一个指向一块存有 10 这个 int 类型数据的堆内存空间的智能指针
std::shared_ptr<int> p3(new int(10));
std::shared_ptr<int> p3 = std::make_shared<int>(10);
//以上 2 种方式创建的 p3 是完全相同
- shared_ptr 模板提供相应的拷贝构造函数和移动构造函数
//调用拷贝构造函数:p4 和 p3 指向同一块堆内存,同时该堆空间的引用计数会加 1
std::shared_ptr<int> p4(p3);//或者 std::shared_ptr<int> p4 = p3;
//调用移动构造函数:std::move(p4) 初始化 p5,会使得 p5 拥有了 p4 的堆内存,而 p4 则变成了空智能指针
std::shared_ptr<int> p5(std::move(p4)); //或者 std::shared_ptr<int> p5 = std::move(p4);
- 注意,同一普通指针不能同时为多个 shared_ptr 对象赋值,否则会导致程序发生异常
int* ptr = new int;
std::shared_ptr<int> p1(ptr);
std::shared_ptr<int> p2(ptr);//错误
3.1.2 std::shared_ptr成员函数
成员方法名 | 功 能 |
---|---|
operator=() | 重载赋值号,使得同一类型的 shared_ptr 智能指针可以相互赋值 |
operator*() | 重载 * 号,获取当前 shared_ptr 智能指针对象指向的数据 |
operator->() | 重载 -> 号,当智能指针指向的数据类型为自定义的结构体时,通过 -> 运算符可以获取其内部的指定成员 |
swap() | 交换 2 个相同类型 shared_ptr 智能指针的内容 |
reset() | 当函数没有实参时,该函数会使当前 shared_ptr 所指堆内存的引用计数减 1,同时将当前对象重置为一个空指针;当为函数传递一个新申请的堆内存时,则调用该函数的 shared_ptr 对象会获得该存储空间的所有权,并且引用计数的初始值为 1 |
get() | 获得 shared_ptr 对象内部包含的普通指针 |
use_count() | 返回同当前 shared_ptr 对象(包括它)指向相同的所有 shared_ptr 对象的数量 |
unique() | 判断当前 shared_ptr 对象指向的堆内存,是否不再有其它 shared_ptr 对象再指向它 |
operator bool() | 判断当前 shared_ptr 对象是否为空智能指针,如果是空指针,返回 false;反之,返回 true |
3.2 std::unique_ptr智能指针
- 与其它智能指针的区别
- 与 std::shared_ptr 指针最大的不同之处在于,unique_ptr 指针指向的堆内存无法同其它 unique_ptr 共享,也就是说,每个 unique_ptr 指针都独自拥有对其所指堆内存空间的所有权
- 作为智能指针的一种,unique_ptr 指针自然也具备“在适当时机自动释放堆内存空间”的能力
3.2.1 std::unique_ptr智能指针的创建
- 通过以下 2 种方式,可以创建出空的 unique_ptr 指针:
std::unique_ptr<int> p1();
std::unique_ptr<int> p2(nullptr);
- 创建 unique_ptr 指针的同时,也可以明确其指向
std::unique_ptr<int> p3(new int);
- 基于 unique_ptr 类型指针不共享各自拥有的堆内存,因此 C++11 标准中的 unique_ptr 模板类没有提供拷贝构造函数,只提供了移动构造函数
std::unique_ptr<int> p4(new int);
std::unique_ptr<int> p5(p4);//错误,堆内存不共享
std::unique_ptr<int> p5(std::move(p4));//正确,调用移动构造函数,p5 将获取 p4 所指堆空间的所有权,而 p4 将变成空指针(nullptr)
3.2.2 std::unique_ptr成员函数
3.3 std::weak_ptr智能指针
- weak_ptr 模板类中没有重载 * 和 -> 运算符,这也就意味着,weak_ptr 类型指针只能访问所指的堆内存,而无法修改它
- 与其它智能指针的关系
- C++11标准虽然将 weak_ptr 定位为智能指针的一种,但该类型指针通常不单独使用(没有实际用处),只能和 shared_ptr 类型指针搭配使用。甚至于,我们可以将 weak_ptr 类型指针视为 shared_ptr 指针的一种辅助工具,借助 weak_ptr 类型指针, 我们可以获取 shared_ptr 指针的一些状态信息,比如有多少指向相同的 shared_ptr 指针、shared_ptr 指针指向的堆内存是否已经被释放等等。
- 需要注意的是,当 weak_ptr 类型指针的指向和某一 shared_ptr 指针相同时,weak_ptr 指针并不会使所指堆内存的引用计数加 1;同样,当 weak_ptr 指针被释放时,之前所指堆内存的引用计数也不会因此而减 1。也就是说,weak_ptr 类型指针并不会影响所指堆内存空间的引用计数
3.3.1 std::weak_ptr指针的创建
- 可以创建一个空 weak_ptr 指针
std::weak_ptr<int> wp1;
- 凭借已有的 weak_ptr 指针,可以创建一个新的 weak_ptr 指针
// 若 wp1 为空指针,则 wp2 也为空指针;反之,如果 wp1 指向某一 shared_ptr 指针拥有的堆内存,
// 则 wp2 也指向该块存储空间(可以访问,但无所有权)
std::weak_ptr<int> wp2 (wp1);
- weak_ptr 指针更常用于指向某一 shared_ptr 指针拥有的堆内存,因为在构建 weak_ptr 指针对象时,可以利用已有的 shared_ptr 指针为其初始化
// wp3 指针和 sp 指针有相同的指针。再次强调,weak_ptr 类型指针不会导致堆内存空间的引用计数增加或减少
std::shared_ptr<int> sp (new int);
std::weak_ptr<int> wp3 (sp);
3.3.2 std::weak_ptr成员函数
成员方法名 | 功 能 |
---|---|
operator=() | 重载 = 赋值运算符,是的 weak_ptr 指针可以直接被 weak_ptr 或者 shared_ptr 类型指针赋值 |
swap(x) | 其中 x 表示一个同类型的 weak_ptr 类型指针,该函数可以互换 2 个同类型 weak_ptr 指针的内容 |
reset() | 将当前 weak_ptr 指针置为空指针 |
use_count() | 查看指向和当前 weak_ptr 指针相同的 shared_ptr 指针的数量 |
expired() | 判断当前 weak_ptr 指针为否过期(指针为空,或者指向的堆内存已经被释放) |
lock() | 如果当前 weak_ptr 已经过期,则该函数会返回一个空的 shared_ptr 指针;反之,该函数返回一个和当前 weak_ptr 指向相同的 shared_ptr 指针 |
4. std::enable_shared_from_this
- 功能
- 如果一个T类型的对象t,是被std::shared_ptr管理的,且类型T继承自std::enable_shared_from_this,那么T就有个shared_from_this的成员函数,这个函数返回一个新的std::shared_ptr的对象,也指向对象t
- 应用场景
- 当类T被share_ptr管理,且在类T的成员函数里需要把当前类对象作为参数传给其他函数时,就需要传递一个指向自身的share_ptr
- 一个主要的场景是保证异步回调函数中操作的对象仍然有效
// 错误地使用this指针
class Foo {
public:
void Bar(std::function<void(Foo*)> fnCallback) {
// async call fnCallback with this
}
}
// Foo::Bar接受一个函数对象,这个对象需要一个Foo*指针,其实要的就是Foo::Bar的this指针,但是这个回调是异步的,
// 也就是说可能在调用这个回调函数时,this指向的Foo对象已经提前析构了。
// 这时候,std::enable_shared_from_this就派上用场了
// 正确的使用方法
class Foo : public std::enable_shared_from_this<Foo> {
public:
void Bar(std::function<void(std::shared_ptr<Foo>)> fnCallback) {
std::shared_ptr<Foo> pFoo = shared_from_this();
// async call fnCallback with pFoo
}
}
// 这样就可以保证异步回调时,Foo对象仍然有效
-
以上是关于C++11常用知识的主要内容,如果未能解决你的问题,请参考以下文章