C++学习笔记 — 由浅入深(侯捷)

文章目录

C++ 程序设计

杂七杂八

  • 编译/链接/运行
    • 预编译Preprocessing主要是对条件预编译指令的处理:宏的展开/头文件引用/把所有的注释都替换为空格/保留所有#pragma(作用是设定编译器的状态或者是指示编译器完成一些特定的动作)
    • 编译Compilation主要是进行代码优化和符号汇总:扫描/语法分析/语义分析/源代码优化/代码生成/目标代码的优化;文本翻译成汇编语言
    • 汇编Assembly根据对应关系把汇编指令转换为本地操作系统对应的机器码,生成可重定位目标文件
    • 链接Linking把多个目标文件合并成一个可执行文件
      • 1 把所有的.o文件的各个段合并起来,其中对符号表段的合并就是符号解析,当一个符号在段中找到多个定义(重定义)或者未找到定义(未定义)就会发生链接错误。符号解析正确后,就会给符号表分配虚拟地址
      • 2 进行符号重定向(就是把指令中所有的无效地址均修改成正确的虚拟地址)
        在这里插入图片描述
    • 加载Loading上一步所生成的可执行文件终于可以被操作系统加载运行了。操作系统会将这个可执行文件中的代码和数据从磁盘复制到内存中,并跳转到该程序的第一条指令处(也叫做入口点,entry point)开始执行。
  • struct和class的区别
    • class 是引用类型,它在堆中分配空间,栈中保存的只是引用;而 struct 是值类型,它在栈中分配空间。class是引用类型,struct是值类型;既然 class 是引用类型,class 可以设为 null;但是我们不能将 struct 设为 null
    • new 一个类的实例时,在栈(stack)上存放该实例在托管堆(Managed Heap)中的地址,而实例的值保存在托管堆(Managed Heap)中。
    • 托管堆分配在被操作系统保留的一段内存区域中,这段内存区域是由 CLR 来管理的,这段内存称之为托管堆。
    • struct(结构)是一种值类型,用于将一组相关的变量组织为一个单一的变量实体,可以将其当作 int、char 这样的基本类型对待
    • 默认继承权限。如果不明确指定,来自class的继承按照private继承处理,来自struct的继承按照public继承处理;
    • 成员的默认访问权限。class的成员默认是private权限,struct默认是public权限。
    • 如果没有多态和虚拟继承,在C++中,struct和class的存取效率完全相同
    • class有显式的初始化构造函数,struct没有;class当只当变量都是公有变量时才能和struct一样用花括号初始化!
  • const修饰问题(成员函数):修饰变量(类也是变量)const放在前面变量定义的前面,修饰函数放在函数括号之后(放在函数䣌前面其实是在修饰返回值);修饰函数实际上就是在告诉编译器,这个函数不会在内部改变参数;const在设计中一定要考虑到,就是不修改的一定加,不加的认为会修改。函数中的const是属于函数签名的一部分的!PS函数签名不看返回值的类型,引用也不看
  • const修饰类成员函数的时候,其实是在修饰this指针
  • 传参的传值形式和引用方式:引用的底层还是指针,但是被C++设计的更加得漂亮
  • friend问题:类内为函数声明友元特性(放在函数最前面),那这个函数可以直接访问该类得私有变量;注意同class的各个objects互为friends
  • this:所有成员函数默认带有this 指针,编译器会自己加上
  • 函数设计中的临时变量问题,返回引用和值问题
  • 拷贝构造和拷贝赋值:initialization & Assignment;参数都是对应类名
  • -(Big Three)
    在这里插入图片描述
  • 拷贝构造函数:copy ctor,深拷贝 / copy op=
  • Stack / Heap
    • stack:存在于某作用域的一块内存空间Memory Space,如一个函数就会形成一个stack;函数内任意的变量都存在于上述stack的;Stack的生命期取决于作用域!
    • heap:system heap,操作系统存在的一块global内存空间,程序通过动态分配Dynamic allocated获得若干区域!new完需要delete,内存泄漏,你使用之后,没有即使归还给系统!
  • new的过程:(分配内存 + 调用构造)
    在这里插入图片描述
  • delete过程:(调用析构 + 释放内存)
    在这里插入图片描述
  • new char[X] <> delete[]:中括号搭配中括号;有没有中括号,不影响内存的释放,而是有中括号会调用多次析构函数!内存泄漏就会出现在类中(当类中有new对象的时候)
    在这里插入图片描述
  • new和delete可以进行重载
    在这里插入图片描述
    在这里插入图片描述
  • new表达式/operator new/placement new/
  • 静态特性静态函数没有this指针;调用静态函数的方法1是通过object调用2是通过class name来调用!单例设计模式,把构造函数放在private里面+初始化一个静态实例:
    在这里插入图片描述
    在这里插入图片描述
  • cout是一种ostream
  • 模板 template<typename T> template<class T>
    • 函数模板不需要尖括号提供类型,编译器会自动进行argument deduction 引数推导!
  • Object Orientated Programming/Design Inheritance继承 / Composition复合 / Delegation委托
  • Composition:has-a,下图是一种复合关系
    • queue拥有着deque,deque这里足够强大,而queue只是拥有deque的部分功能,这种设计模式叫Adapter
    • 组合,构造由内往外,析构由外往内
      在这里插入图片描述
  • Delegation (Composition by reference):有指针指向某个类;前面复合关系两个类的生命周期是一致的!而委托关系这不一定!
    在这里插入图片描述
  • Inheritance:is-a
    在这里插入图片描述
  • 注意一般继承都是 public继承,表示 is a的关系,而采用 private继承的时候,其设计思想其实算是 has a的关系!
  • 继承+虚函数+多态
  • 虚函数virtual: 设计非虚函数,虚函数和纯虚函数的动机是 希不希望派生类对其进行重写override,分别是 不希望重写(有默认定义) / 希望重写(有) / 一定要重写(无)!
    • 模板方法设计模式:把需要单独放在子类中定义实现的先定义成虚函数
  • 继承+复合
  • 委托+继承
  • 23种设计模式 CSDN博客

转换函数和构造函数

  • 转换函数:operator double() const {return (double)(..)};
    在这里插入图片描述
  • non-explicit-one-argument ctor:
    在这里插入图片描述
  • 转换函数 + 非显性单参数构造函数 比较
    在这里插入图片描述
  • explicit-one-argument ctor:explicit关键字90%用在构造函数前面!
    在这里插入图片描述

point-like classes 智能指针/迭代器

  • ->操作符可以无限进行,而不是只能使用一次
    在这里插入图片描述
    在这里插入图片描述

function-like classes 仿函数

  • STL中的
    在这里插入图片描述

member template 成员模板

在这里插入图片描述

Specialization 模板特化

  • 和泛化相对,更加局部性的特征化
    在这里插入图片描述
  • partial specialization 模板偏特化:① 个数上的“偏” ② 范围上的“偏”
    在这里插入图片描述

template template parameter 模板模板参数

在这里插入图片描述

  • 下图deque已经不算是模板参数了,已经是类型了
    在这里插入图片描述

Variadic Template 数量不定的模板参数

在这里插入图片描述

reference

  • 函数中参数加不加引用,不会改变函数的签名!即如果函数定义只有入口参数有没有加&的话,其函数签名会相同!导致冲突!

this

  • 通过对象调用函数,this就是这个对象的地址
  • this就是给对象提供了一个寻找的方法(每个非静态成员函数都被编译器隐含着一个this指针)

virtual 虚函数/虚指针vptr/虚表vtbl

  • 关于继承:继承变量内存+继承函数的调用权
  • 含虚函数的类(抽象类)的动态绑定图示
  • 下图的下方的代码中的p,可以是this指针,那么下方的代码就是在调用p对应对象的虚函数表中的第n个虚函数,编译器在将this隐含的赋值给了这个成员(虚)函数。
    在这里插入图片描述
  • Dynamic Binding动态绑定相对的是静态绑定,静态绑定直接访问的是call某个内存位置©
  • C++的函数调用有两个方式:静态绑定和动态绑定;静态绑定就是汇编call+地址;动态绑定就是符合,(对象是指针/指针是向上转型/调用的是虚函数)情况时,就是要动态绑定!
  • 再一个例子
    在这里插入图片描述

const

在这里插入图片描述

STL 体系结构和内核分析

  • STL源码剖析 STL泛型编程的思维,最新的也是加了面向对象思维,class多了很多切分
  • Container <- Iterators -> Algorithm (Functors)
  • C++ standard Library / Standard Template Library
  • 6大组件
    在这里插入图片描述
  • STL的区间是取得 前闭后开 的样子!
  • 容器
    在这里插入图片描述
  • 分配器allocator:和new/malloc区别,需要记住分配的内存大小,以方便之后的dellocator

操作符重载和模板知识

  • 四个运算符不能重载:::..*?:
  • 三个运算符不能创建:**<>&|
  • 三个运算符重载会失去其特性:&&||(Short-circuit evaluation), 依次执行返回最左边表达式的值
  • ->操作符重载要求必须返回 一个指针或者 一个对象(引用或者值)
  • 重载不能修改运算符的procedure / grouping / #operands(优先级,类别和操作数)
  • 类模板 Class Template
    在这里插入图片描述
  • 函数模板 Function Template
    在这里插入图片描述
  • 成员模板 Member Template
    在这里插入图片描述
  • 变量模板 Variable Template (Since C++14)
    在这里插入图片描述
  • 模板特化 Specialization
    在这里插入图片描述
  • 偏特化 Partial Specialization
    在这里插入图片描述
    在这里插入图片描述

OOP vs. GP

  • Object Oriented Programming
  • Generic Programming
  • OOP:旨在将Datas和Methods联系在一起
    在这里插入图片描述
  • GP:旨在将Datas和Methods分开,操作符重载在GP中有重要的地位!
    在这里插入图片描述
  • STL的六大部件:Containers / Allocators / Algorithms / Iterators / Adapters / Functors

分配器 Allocators

  • malloc / new
  • VC等很多Allocators,会有很多额外开销OverheadD
    在这里插入图片描述
  • 容器如果使用这种allocator,会多很多内存(Cookie),导致内存占用大,效率低,尽量减少malloc次数
  • G2.9,标准库STL里面自定义了alloc数据结构,元素不带Cookie
    在这里插入图片描述
  • G4.9的容器又改回到new和free了 …

容器

容器之间的实现关系和分类

  • heap里面有一个vector
  • set里面有一个vector
    在这里插入图片描述

深度探索 - LIST

  • G2.9版本,节点指针 void_pointer 定义为 void*
    在这里插入图片描述
  • List<T>::iterator
    在这里插入图片描述
  • ++i (prefix form) / i++ (postfix form):++++i 整数可行,等于+2;i++++不可行反正,所以这里postfix形式的++,返回的是值而不是引用,即一个临时变量,所以二次++就会报错(因为临时变量不能被累加)
    在这里插入图片描述
  • LIST迭代器在G2.9和G4.9上面的差别
    在这里插入图片描述
  • G4.9版本的list继承关系更多更混乱!① 内存从4变成8,即 _M_prev: _list_node_base 和 _M_next:_list_node_base两个指针,② 而 2.9版本是 List_node* 一个指针4个字节!
    在这里插入图片描述

Iterator设计原则和Traits

  • iterator是算法和容器的桥梁
  • 某个算法函数 为 rotate
  • 下图中可以看出 rotate() 需要知道iterator的两个相关对象
  • 算法提出问题,迭代器回答问题,问题有:
  • value_type 表示元素的类型,
  • different_type 表示元素间距离的类型,
  • iterator_category 表示迭代器的类型(随机访问?前向?…)
    在这里插入图片描述
  • 另外还有 reference_type 和 pointer_type 两个"问题",但是这两个问题整个STL库中尚未找到!
  • 总结,iterator 得提供5种associated types,下图是算法和迭代器之间的 “直接问答”:
    在这里插入图片描述
  • 当没有用 iterator, 而是一般的pointer,将pointer视为iterator的退化形式!而指针无法直接回答算法的问题,所以加上一个中间层 Traits 来兼容 Pointer

Traits

在这里插入图片描述

  • 使用偏特化来兼容 pointer 和 算法 的问答行为在这里插入图片描述
  • 完整的 iterator_traits
    在这里插入图片描述
  • 各种 Traits !type / iterator / char / allocator / pointer / array traits

深度探索 - VECTOR

在这里插入图片描述

  • 两倍增长 (push_back()调用时)
    在这里插入图片描述
    在这里插入图片描述

vector的迭代器

在这里插入图片描述

  • G2.9占用3 x 4 = 12内存(start+finish+end of storage)
  • G4.9 也占用 12字节的内存
    在这里插入图片描述
  • vector的迭代器
    在这里插入图片描述
    在这里插入图片描述

深度探索 - ARRAY

在这里插入图片描述
在这里插入图片描述

深度探索 - FORWARD_LIST

  • 单向链表
    在这里插入图片描述

深度探索 - DEQUE

  • 双端队列:连续是假象,分段是事实!
  • 默认实现采用vector,2倍成长!
    在这里插入图片描述
  • 占用内存:4 * 2 + (4 * 4) * 2 = 40
  • _deque_buf_size() 第二个参数使用0,则会使用默认的值 (sz < 512) ? size_t(512 / sz) : size_t(1)
    在这里插入图片描述
  • 一个迭代器占用16字节
    在这里插入图片描述

deque<T>::insert()

在这里插入图片描述
在这里插入图片描述

deque如何模拟连续空间

  • 全是 deque iterator 的功劳
  • front() back() size() empty() []
    在这里插入图片描述
  • * -> -
    在这里插入图片描述
  • ++ –
    在这里插入图片描述
  • += -= - + []
    在这里插入图片描述
    在这里插入图片描述
  • deque 程序结构
    在这里插入图片描述
    在这里插入图片描述
  • 注意扩充2倍的时候,会把原map放在之后的中段

深度探索 - QUEUE/STACK

  • 基于Sequence数据结构的 适配器模式 (C++专门叫适配器模式)
    在这里插入图片描述
    在这里插入图片描述
  • queue / stack 的底层也可以用list
    在这里插入图片描述
  • queue 不可以选择vector 作为底层 / stack可以:因为vector没有 pop_front()函数
  • queue和stack不可使用set或者map作为底层结构!!

红黑树 RB_TREE

  • 红黑树:Red-Black tree,平衡二叉搜索数 balanced binary search tree
  • 平衡有利于 insert 和 search
  • 中序遍历为升序,所以其 迭代器++行为 是按照中序遍历的顺序进行
  • RB树应该不能允许程序修改键值(map等数据结构要求),但是程序上没有严格规定
  • insert_unique() / insert_equal():前者要求插入的键值不能和已知冲突(不可重复键),后者不要求(可重复键)!
    在这里插入图片描述
  • 红黑树,模板参数有5个:key的类,value的类(包括ket+data),从value中取出key的方法类,比较函数,内存分配器!
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 此外,4.9中插入函数,insert_unique() 变为 _M_insert_unique()!
  • Handle + body 模式 桥接模式
    在这里插入图片描述
  • 其实 set/multiset/map/multimap 其实也算是底层采用rb_tree的 适配器模式!

深度探索 - SET/MULTISET

  • 以RBtree为底层结构,所以元素有自动排序的特性
  • 排序依据为 key,set/multiset 的value(key+value)其实和key合一
  • 无法使用其迭代器修改key值!
  • set 的insert()函数使用rb_tree()的insert_unique(),其key独一无二
  • multiset的insert()函数使用rb_tree()的insert_equal(),其key可以重复

SET

  • 其 迭代器 定义成了const_iterator常迭代器,即不允许改变其指向的元素!
    在这里插入图片描述
  • 而 VC中没有identity仿函数
    在这里插入图片描述

深度探索 - MAP/MULTIMAP

  • 同样使用rb_tree为底层结构
  • 和set不同在于,其key不等于value
  • 同样 map对应 insert_unique(); multimap 对应 insert_equal()
  • pair<const key T>,即键值为常,不能修改!
    在这里插入图片描述
    在这里插入图片描述
  • map的operator[] 是独特的
    在这里插入图片描述

哈希表 HASHTABLE

  • 内存空间足够或者不足时
  • 不足的时候,取余下标,出现下标冲突!
    在这里插入图片描述
  • 发生碰撞:拉链法,某个下标上 超过了bucket_size, 就需要扩充大小!rehashing
    在这里插入图片描述
  • 容器hashtable:GNU-C 是单向链表 VC是双向链表
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 标准库中没有 提供 hash<std::string>
  • 得到哈希值后,怎么放到篮子里面?
    在这里插入图片描述
  • load_factor = size / bucket_count
  • max_load_factor = 1
  • max_bucket_size = 357913941

深度探索 - UNORDERED_SET/_MULTISET/_MAP/_MULTIMAP

迭代器 iterator

  • 分类:
    在这里插入图片描述
    在这里插入图片描述
  • 容器中没用到的迭代器:
  • istream_iterator的iterator_category:input_iterator
  • ostream_iterator的iterator_category:output_iterator
    在这里插入图片描述
    在这里插入图片描述
  • iterator_category 对算法的影响:
    在这里插入图片描述
    在这里插入图片描述
  • iterator traits 和 type traits 对算法的影响
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • trivial / no-trivial
    • Trivial(平凡)和Non-Trivial(不平凡)是对于class(类)的或者类中的四个函数而言的:构造函数 | 拷贝构造函数 | 赋值函数 | 析构函数;其中Trivial(平凡)的概念本人的理解是无意义的,Trivial是相对于Non-Trivial而言的;
    • 对于Non-Trivial而言的,如果上面四种函数满足以下三点任意一项或一项以上:有基类;显式(explict)定义了以上四种函数一种或以上;类里有非静态非POD的数据成员。有意义(Non-Trivial)的函数都有一些“多余”的操作,和系统自动创建的默认缺省函数有些差别。(POD(Plain
      Old Data)是指C风格的struct结构体定义的数据结构或者C++的内建类型)
    • 有意义(Non-Trivial)的类则是含有Non-Trivial的函数。

在这里插入图片描述

  • 算法源码 对 iterator_category 只有暗示:只在模板参数的命名有了暗示,template <class RandomAccessIterator>
    在这里插入图片描述
  • 逆向迭代器:reverse iterator,rbegin(),rend() 是一种 iterator Adapter
reverse_iterator
rbegin() { return reverse_iterator(end());}
reverse_iterator
rend() {return reverse_iterator(begin());}

在这里插入图片描述

算法

  • Algorithm:看不见Container,对其一无所知,一切从iterator提供信息
    在这里插入图片描述

算法 (11个例子)

accumulate

  • 累次处理函数
  • binary_op() 二元操作符函数
struct myOp {
	int operator() (int x, int y) {return 3 * x + y;}
} myOp;

或者
int myOp(int x, int y) {return 3 * x + y;}
在这里插入图片描述

for_each

  • 对容器中每个元素采用相同的操作
    在这里插入图片描述

range-based for statement

replace / replace_if / replace_copy

  • 替换
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

count / count_if

  • 计数
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

find / find_if

在这里插入图片描述

sort

在这里插入图片描述

binary_search

  • 值已经是拍好序的
  • 二分查找,是否存在
    在这里插入图片描述

仿函数 functors

  • 写法类似于
    在这里插入图片描述
  • 仿函数的可适配条件 Adaptable
  • STL 规定 每个Adaptable Function 都应该挑选适当的继承者,因为可能会问问题,问一些 类型 名
    在这里插入图片描述

适配器 Adaptors

  • A获取B的特性,要不继承,要不内含
  • 适配器,采用内含方式(组合方式)
  • 适配器修饰什么,就得表现的像什么
  • 分类:
    • 容器适配器,stack / queue
    • 函数适配器,binder2nd,把第二个元素绑定为40
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      • 新型适配器 bind
        在这里插入图片描述
    • 迭代器适配器,reverse_iterator 逆迭代器 / inserter 带插入功能的迭代器
      在这里插入图片描述
      在这里插入图片描述
  • X 适配器:ostream_iterator 输出流迭代器 / istream_iterator 输入流迭代器
    在这里插入图片描述
    在这里插入图片描述

补充知识

一个万用的hash function

  • 0x9e3779b9:在这里插入图片描述
    在这里插入图片描述
  • 所有代码
    在这里插入图片描述
  • 哈希表的三种形式:
    在这里插入图片描述
  • 形式三,以偏特化形式实现 Hash Function
    在这里插入图片描述

tuple

  • 多种数据类型的整合 组合
  • tuple<int, float, string> t1(4, 4.3, "nico");
    在这里插入图片描述
    在这里插入图片描述

type triats

  • trivial / non-trivials (构造函数 / 析构函数 重不重要!)
    在这里插入图片描述
  • 就是为 类记录各种traits,以便于回答 算法等提出的问题!
  • C++ 11 以后更多 。。。
    在这里插入图片描述
  • type traits 的定义!
    在这里插入图片描述

cout

在这里插入图片描述

moveable 元素对于 vector / … 等 速度效能的影响

  • std::move(X)
  • 写一个 moveable class
  • &&:reference of reference 在这里插入图片描述
    在这里插入图片描述在这里插入图片描述
  • move 之后,原来的变量不在使用,因为为了避免指针 共享,销毁了前一个原指针(浅拷贝 + 销毁原指针)
  • 而深拷贝为什么慢呢?因为深拷贝需要一个一个插入,而浅拷贝只用把头尾指针交换下就行了(共享指针),而原指针作废,所有十分快!
  • string也带有move功能

C++2.0 新特性

Variadic Templates

Spaces in Template Expressions

Unifrom Initailization

Initializer List

Explicit for ctors

Range

default / delete

Alias Templates

Template template parameter

Type Alias, noexcept, override, final

decltype

lambdas

Rvalue reference & Move Semantic

Perfect forwardings

Move-aware class

新的 容器

Hash function

Tuple

C++ 内存管理

内存分配的各个层次

在这里插入图片描述

  • C++ memory primitives
    在这里插入图片描述
  • VC编译器下的new过程是
    在这里插入图片描述
  • 各自的好处:GP中Container和Algorithm可分开操作,之间使用Iterator联系;Algorithm通过Iterator确定操作范围和获取数据;
  • list不能用algorithm的全局sort就是因为后者需要操作对象具有随机访问的迭代器!
    在这里插入图片描述
  • 所有algorithm内涉及到的元素本身的操作,无非就是比大小

C++ 并发和多线程(^)

CRT Startup code 说明(启动码)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值