C++小记
文章平均质量分 66
Android_chunhui
人不一定能什么都擅长,有自己的特点就好!
展开
-
性能优化篇
因为 ProtoBuf 采用的是 Arena 内存分配器策略,有些场景会比 C++的 Class 内存管理复杂,当有大量内存分配和释放的时候会比 Class 的性能差很多。而且 Protobuf 会不断分配和回收小内存对象,持续地分配和删除小内存对象导致产生内存碎片,降低程序的内存使用率,尤其是当协议中包含 string 类型的时候,性能差距可能有几倍。内存碎片:频繁分配和释放不同大小的对象,可能导致内存碎片,降低内存的使用效率。原创 2024-06-17 17:42:27 · 211 阅读 · 0 评论 -
函数定义与声明
在C98中inline用于函数内联,但是在C++11以及更高的版本中编译器内联函数不再完全参考inline关键字。inline是一种弱修饰符,可修饰函数和命名空间(C++17)。原创 2023-01-19 16:10:27 · 182 阅读 · 0 评论 -
并行下的效率与安全
cacheline被读取进来后会拷贝到内核私有的L1/L2cache下,当原子变量被修改后,会通知cpu的其他核心来同步变量所在的cacheline(cpu一致性同步)。这就存在falsesharing现象当某个变量被多个核心共享时,一个核心对其进行修改就会导致其所在的cacheline失效,需要重新从内存读取,cacheline中的其他变量也要等待缓存同步而变慢,严重影响整体性能。......原创 2022-07-24 21:51:00 · 330 阅读 · 0 评论 -
c++探险--有虚函数时的继承
父类没有虚函数我们都知道子类在继承父类的时候,会将父类的变量和虚表指针继承下来保存到自己的内存里(即使父类private变量的内存也会继承下来,只会无法访问到),也就是子类对象内存中存储着一个父类对象。如果使菱形继承,那么"菱形"底部的类就会存储两份"菱形"顶端的类对象内存,通过虚继承可优化成一份,暂且不表。class Base {public: int a;private: int b;};class Sub : public Base {int c;};#mermaid-svg.原创 2021-06-20 18:15:27 · 253 阅读 · 0 评论 -
写出优雅代码
目录一. 封装,继承,多态封装继承多态二. 设计原则单一职责一. 封装,继承,多态封装尽可能隐藏一个模块的实现细节。原因:增加调用者负担,使用者在使用你的类时还要知道实现细节。耦合性。比如类内部有个成员是vector,那么外部应该用push_back等方法来操作,有一天需要换城map,那么所有调用方的代码都得改。应该对外界提供访问数据的方法(getter、setter);而不是直接将数据等实现细节暴露出去。继承不能仅仅因为is-a和is-kind-of就定义为继承关系,必须是派生类能够适原创 2021-05-27 02:11:57 · 131 阅读 · 0 评论 -
c++引用
c++引用包含左值引用和右值引用,因为引用都是变量,因此右值引用是左值。左值指变量,右值指临时对象,字面值(16,“string”,13+2)。当函数参数为T&&时(其中T时模板类型),是万能引用,传入参数是左值,T&&就变成左值引用,否则T&&变成右值引用。template<typename T> void f(T&&a...原创 2019-12-24 11:55:18 · 171 阅读 · 0 评论 -
哈希表
哈希表又称散列表,存储键值对,主要操作有插入,删除,查找。哈希表底层是一个数组,首先将key通过哈希函数计算哈希值,也即数组下标,然后对位置上的元素执行插入删除,查询。三种操作时间复杂度均为O(1)O(1)O(1),耗时操作在哈希函数计算和哈希冲突的处理上。哈希函数(*)哈希函数的要求是,映射均匀,降低哈希冲突的几率;计算简单,节省时间。直接定址法使用key的线性函数作为哈希函数,H(k...原创 2019-12-21 20:54:30 · 313 阅读 · 0 评论 -
模板相关
一. 编译过程首先介绍C++程序的编译过程。编译器以源文件为编译单元,编译过程分为四个阶段:预处理,编译,汇编,链接。预处理:处理头文件和宏定义。首先根据寻找源文件中所包含的头文件,进入头文件进行宏替换,根据条件编译修改源程序。然后把头文件的内容全部添加到当前原文件里,形成一个中间c文件。编译:对中间的c文件进行语法检查,并将源代码编译成汇编文件。汇编:将汇编翻译成二进制的机器码...原创 2019-12-20 17:28:30 · 185 阅读 · 0 评论 -
STL中vector的简单实现
new实现了分配内存和初始化的整合,但是在分配大块内存时,对所有位置都调用构造函数是低效的,应该在使用时才初始化该位置。所以必须单独进行内存分配和初始化。依赖于allocator的T* allocate(size_t); //分配内存construct(T*, args);//构造函数destroy(T*);//析构deallocate(T*, size_t);//释放内存cla...原创 2019-09-05 00:18:48 · 216 阅读 · 0 评论 -
c++智能指针以及shared_ptr实现
简化版shared_ptr初始化两种方式:传指针int * a = new int(1);shared_ptr<int> p(a), q(a);//这时两个智能指针对象p,q里的计数无法同步,都是1.//避免这种//尽量使用shared_ptr<int> p(new int(1));make_sharedshared_ptr<int>...原创 2019-12-18 17:44:47 · 329 阅读 · 0 评论 -
c++11新特性
move语义 与forward完美转发减少内存复制成本将不再需要的变量,取消它对资源的的持有权。对临时变量(如函数中的参数)的复制,只复制临时对象中的指针,然后将其置null,避免了内存拷贝,提高了效率。std::move本质上是类型转换,讲左指类型变为右值类型,从而可以调用移动构造或移动赋值操作符。override与finaloverride:对重写的虚函数进行修饰,在编译期...原创 2019-09-26 11:44:31 · 182 阅读 · 0 评论 -
c++编译期间和运行期间
编译期编译期主要是编译器的预处理和编译C++代码,(汇编和链接是对机器码不考虑)。预处理阶段:宏替换 #define,条件编译 #ifndef #endif头文件编译:执行类型检查,语法检查,以及为变量确定内存分配大小,这些变量包括全局或静态变量,栈上的变量。所以说数组大小必须是编译期间确定的值,编译期间并不给变量分配内存,而是确定好内存大小,等到运行分配。sizeof编译期运...原创 2019-09-25 01:28:43 · 2306 阅读 · 2 评论 -
哲学家就餐问题
有五个哲学家,每个哲学家之间有一只筷子,必须同时获得两只筷子才能进餐。平时一个哲学家进行思考,饥饿时便试图取用其左、右最靠近他的筷子,只有在他拿到两支筷子时才能进餐。进餐完毕,放下筷子又继续思考。在就餐时会引发两个问题:1.死锁 :每个哲学家持有一只筷子,等待相邻哲学家释放另一只筷子而形成循环等待的状态。2.饥饿:所有哲学家同时持有一只筷子,因无法得到两只而同时释放,发现条件满足又同时拿起...转载 2019-09-18 15:49:48 · 457 阅读 · 0 评论 -
红黑树与AVL树
AVL树平衡二叉树又称为AVL树,是一种特殊的二查搜索树。任意节点左右子树高度之差的绝对值不超过1。平衡二叉树的搜索和插入,删除时间复杂度都是O(logn).对于普通二查搜索树,当树的结构变成线性时,查找时间复杂度为O(n)。如何实现平衡:节点分布:左左型 右旋右右型 左旋左右型 先左旋变成左左型,再右旋右左型 先右旋变成右右型,再左旋左旋:逆时针旋转,父节点被右孩...原创 2019-09-17 11:18:06 · 353 阅读 · 0 评论 -
c++冷知识
表达式计算方向printf和cin是从右往左计算.其他表达式从左往右计算,比如逗号表达式,但是逗号表达式返回值是最右边的值。逗号运算符优先级最低,所以要加括号。int b[5] = { 1,2,3,4,5 };int* p = b;printf("%d, %d\n", *(p), *(++p));//输出2, 2int i = 1;int a = (2,i=3, i);cou...原创 2019-09-11 19:00:10 · 265 阅读 · 0 评论 -
设计模式
工厂模式适合于同种类型的产品。class Tank {public: virtual string type() = 0;};class Tank59 :public Tank {public: string type() override { cout << "tank59::" << endl; return "Tank59"; } };c...原创 2019-09-09 21:50:54 · 153 阅读 · 0 评论 -
typedef和using
typedef :后面用变量定义的方式,指定变量名为类型的别名。typedef定义的是类型别名,所有使用别名的地方都等价于使用类型,也会进行语法检查。函数指针: typedef void (*f) (int, const std::string&); f func = 函数地址;数组的引用: typedef int(&Arr)[10]; int a[10]; Ar...原创 2019-09-09 08:55:41 · 359 阅读 · 0 评论 -
使用双指针参数传递
在C++中作为函数传递有值传递和地址传递两种。我们一般知道要将一个变量传入函数并希望变量值能发生改变,必须使用地址穿传递,将指向该变量的指针传入。int num = 1;int* p = #void func(int* p){ *p = 3;}func(p);cout << num; //3同样如果是一个指针变量,想要改变它的值也要传入他的指针,才能能够发生值的改原创 2016-10-16 15:46:10 · 974 阅读 · 0 评论 -
转载:Thinking in C++之1.继承与组合概念、区别及优缺点
1.什么是继承A继承B,说明A是B的一种,并且B的所有行为对A都有意义eg:A=WOMAN B=HUMANA=鸵鸟 B=鸟 (不行),因为鸟会飞,但是鸵鸟不会。2.什么是组合若在逻辑上A是B的“一部分”(a part of),则不允许B从A派生,而是要用A和其它东西组合出B。例如眼(Eye)、鼻(Nose)、口(Mouth)、耳(Ear)是头(Head)的一部分,所以类Head应该由类Eye、Nos转载 2016-10-17 16:08:46 · 402 阅读 · 0 评论 -
转载:c++虚函数的作用
转载地址:http://blog.csdn.net/dqjyong/article/details/7644898 最近面试c++研发的职位,面试官们问到最多的问题的什么是虚函数,虚函数的作用,为什么要有虚函数以及虚函数的使用等等相关的问题。经过各种资料的查找,我觉得还是要从头到尾的重新认识一下虚函数。 我们都知道,c++为了与C语言能够兼容,c++做出了很大的牺牲,包括保留了struct转载 2016-10-17 16:41:57 · 330 阅读 · 0 评论 -
数组指针和指针数组的使用
转载地址:http://www.jb51.net/article/37377.htm 数组指针与指针数组的区别在于:数组指针p是一个指针,而指针数组p是一个存放N个指针变量的数组。 一、数组指针 int (*p)[n] 用于指向一个二维数组。 重点:()优先级高([]、()的优先级是一样的,但它们的方向是从左至右的,所以先运行括号里的*p),首先说明p是一个指针,指向一个整型的一维数组,这转载 2016-10-18 20:47:10 · 610 阅读 · 0 评论 -
运算符重载使用
初学C++的时候对运算符重载的参数问题一直很迷惑,为什么有时候IDE提示参数过多呢?实际上运算符重载有两种形式:重载为成员变量和重载为友函数的形式。重载为成员变量: 即将重载函数作为类的成员变量去定义。这时候函数有一个是隐含的参数this,就是说自动传入了一个类变量(重载函数好像比正常情况下少一个参数),这时重载函数中可以去访问类中任何字段。在系统编译时会这样调用重载函数 op1.operato原创 2016-10-18 22:23:46 · 349 阅读 · 0 评论 -
C++之STL中常用关联容器使用方法
在STL中常用的关联容器有set和map,其他multiset和multimap是这两个容器的扩展,区别就是打破了键值得唯一性,而在set和map中键值是唯一的,即使插入两个相同键的数据,在容器中也只保留一个。set容器内部只有键值而没有实值(我也不知道为什么还能称之为关联容器),而map里存放着元素是pair<T1,T2>对象。set和map内部都实现了红黑树的结构就是平衡搜索树。所以它的优势是原创 2017-02-25 01:03:51 · 470 阅读 · 0 评论 -
c++ split的两种实现
#include <iostream>#include <vector>#include <map>#include <algorithm>#include <string>#include <iomanip>using namespace std;//索引实现vector<string> spl原创 2018-08-10 15:26:21 · 1389 阅读 · 0 评论 -
类,结构体,联合体内存大小分析
结构体内存的数据经过对齐后,那么CPU可以整块地将内存数据读取进来,提高效率。结构体内存分析满足两点:(1)计算变量偏移量:该变量的偏移量必须是min(默认对齐参数,其类型所占字节数)的整数倍。(2)计算结尾偏移量:最终所占字节数必须是成员所占最大字节数的整数倍。所以说,结构体或者类中成员变量按照所占字节递增或递减顺序排放是最省内存的。默认对齐参数:在window VS中为8; 在l...原创 2019-08-15 10:15:08 · 451 阅读 · 0 评论 -
大端与小端模式
大端模式:低地址存储高字节,高地址存储低字节;小端模式:低地址存储低字节,高地址存储高字节。如:0x1234,注意计算机是以字节为基本存储单位的。大端: 0x12 0x34小端:0x34 0x12所以判断大小端的方法:int main(){ unsigned short a = 0x1234; unsigned char* ch = (unsigned char*)&a;...原创 2019-08-15 11:43:22 · 1161 阅读 · 0 评论 -
进程与线程
线程与进程的区别线程是进程的一部分,线程又被称为轻量级进程。系统为进程分配内存资源,却不会为线程分配资源,多个线程共享所在进程的资源。 协程协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,基本没有内核切换的开销,所以上下文的切换非常快。 进程间的通信方式及其优缺点(1)管道(pipe)(2)信号(signal)...原创 2019-08-24 11:45:46 · 250 阅读 · 0 评论 -
生产者消费者模型以及死锁问题
消费者与生产者由于存在于不同的线程,却要访问同一资源,所以容易访问冲突。三种关系实现安全访问:消费者与消费者之间 互斥关系生产者与生产者之间 互斥关系生产者与消费者之间 互斥同步关系其中互斥量(mutex)实现互斥关系。互斥量是一个标志量,一个线程对互斥量加锁,其他线程在对其加锁时就会阻塞从而实现互斥。条件变量实现同步,但要借助互斥量。当阻塞条件满足时,条件变量阻塞当前线程,并解...原创 2019-08-24 16:46:50 · 3268 阅读 · 0 评论 -
C++基础知识总结
堆与栈的区别c++中内存分为栈,堆,全局/静态存储区,常量存储区, 代码区。栈:(1)由编译器负责分配释放,用于存储静态变量,函数参数等。 (2)内存连续,先入后出,不会产生内存碎片。堆: (1)由程序员负责分配释放,如new, malloc生成堆内存。如果忘记回收会造成内存泄漏,直到程序结束才会被释放掉。(2)内存不连续,频繁的new/delete会产生大量碎片,降低程序效率。指...原创 2019-08-15 18:16:58 · 549 阅读 · 0 评论 -
网络
OSI七层协议和五层协议各层常见协议:物理层:IEEE802协议数据链路层:MAC协议网络层:IP, arp地址解析协议运输层:Tcp,udp会话层:SQL表示层:JPEG,MPEG应用层:SMTP邮件地址解析, http, ftp Tcp与Udp区别tcp是面向连接的,可靠的数据流传输,udp是非连接的,不可靠的数据报传输。tcp连接是点到点的,而udp...原创 2019-08-25 00:39:00 · 183 阅读 · 0 评论 -
c++对象内存布局
基础知识内存分为:全局静态存储区,代码区,常量存储区,堆,栈。其中全局静态存储区存放全局变量和所有静态变量(类成员和外部定义的静态变量)。一切函数实现存放在代码区,栈存放函数体内部的局部变量,函数参数,返回值。成员变量:静态成员变量存在全局静态存储区,不占用对象内存。非静态成员变量存储于对象内存,还要加上对齐的字节。成员函数:非静态成员函数:函数参数列表中有默认的指向对象指针的参...原创 2019-09-08 11:37:29 · 238 阅读 · 0 评论 -
函数返回值与参数传递
对结构体返回有些疑问,我在函数内部定义了一个结构体并打印出他的地址,又在main函数中定义一个结构体等于函数返回再打印地址,得到的结果竟然是一样的。今天看到一篇很好的博文,记录如下。原博文地址:http://blog.csdn.net/stillvxx/article/details/41409949(1)函数参数传递是值传递(2)函数的返回值也是值传递当实参要传入函数时,内存中会分配形参内存,原创 2016-10-24 09:28:12 · 1427 阅读 · 0 评论