![](https://img-blog.csdnimg.cn/20201014180756757.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
C/C++
文章平均质量分 78
swbb
这个作者很懒,什么都没留下…
展开
-
近期问题汇总
栈和堆的区别、优缺点inline的优缺点构造函数和析构函数是否可以调用虚函数构造函数是否可以定义为虚函数在c++中怎么实现某个方法只调用一次?原创 2024-05-17 17:12:05 · 704 阅读 · 0 评论 -
简单问题汇总
vector是可变大小数组的序列容器,拥有一段连续的内存空间,并且起始地址不变,因此能高效的进行随机存取,时间复杂度为o(1);但因为内存空间是连续的,所以在进行插入和删除操作时,会造成内存块的拷贝,时间复杂度为o(n)。当数组中内存空间不够时,会重新申请一块内存空间并进行内存拷贝。vector使用动态分配数组来存储它的元素,当新元素插入时候,这个数组需要被重新分配大小,为了增加存储空间,其做法是,分配一个新的数组,然后将全部元素移到这个数组。原创 2024-05-10 17:37:14 · 574 阅读 · 0 评论 -
tiny-Tcmalloc(高并发内存池)
当前项目是实现一个高并发的内存池,它的原型是google的一个开源项目tcmalloc,tcmalloc全称Thread-Caching Malloc,即线程缓存的malloc,实现了高效的多线程内存管理,用于替代系统的内存分配相关的函数(malloc 、free)。提高动态申请的效率减少陷入内核的次数减少系统内存碎片提升内存使用率尽量减少锁竞争应用于多核多线程场景。原创 2024-05-05 15:39:53 · 906 阅读 · 0 评论 -
深入解析重定向操作—dup2函数
在开始深入解析dup2函数之前,我们先来了解一下它的基本概念。dup2函数是Unix/Linux系统提供的一个系统调用函数,其作用是复制文件描述符,并将其指定为新的文件描述符。简单来说,dup2函数可以将一个已存在的文件描述符复制到另一个文件描述符上,并且可以自定义新文件描述符的编号。dup2函数作为Unix/Linux系统中重要的系统调用之一,在计算机系统编程中具有广泛的应用。通过本篇博客,我们详细介绍了dup2函数的原理、用法和常见的使用场景,并提醒读者注意一些使用上的注意事项。原创 2024-03-26 21:28:25 · 595 阅读 · 0 评论 -
Linux中execl函数详解
exec其实并不是一个函数,而是由六个以exec开头的函数所构成的一个函数族,如下图所示其中是最常用的函数,我们就来说一下execl函数我们来说明一下execl函数所需要的四个参数①标识符可以理解为编程时使用的“名字”,像命令 ls -a 中的ls就是标识符,是这个命令的“名字”,文件的文件名就是标识符,是这个文件的“名字”。②参数很好理解,像命令 ls -a 中的 -a 就是参数,函数move(int a, int b)中的整型变量a和整形变量b就是参数。原创 2024-03-25 21:51:33 · 1187 阅读 · 0 评论 -
一个简易的基于线程池的TCP的任务处理
【代码】一个简易的基于线程池的TCP服务器客户端的任务处理。原创 2024-03-22 17:39:09 · 722 阅读 · 0 评论 -
【项目设计】基于MVC的负载均衡式的在线OJ
客户端向服务器的oj_server发起请求,有可能是请求题目的列表、请求特定题目的编写、请求代码提交;对于请求题目列表和编写,只需要向文件或MySQL获取数据,并显示成网页即可,但是提交代码的时候,我们就要考虑多用户提交的情况,所以oj_server在收到不同客户端发来的提交代码的请求时,就需要负载均衡式的选择后端的complie_server进行编译并运行,然后反馈最终结果。原创 2024-03-21 18:46:09 · 985 阅读 · 0 评论 -
学完Efficient c++ (53-55)
Boost 是若干个程序库的集合,并且当中的许多库已经被 C++ 吸纳为标准库的一部分。不过在现在的 Modern C++ 时代,是否该在项目中使用 Boost 仍然有一定的争议,一些 Boost 组件并无法做到像 C++ 标准库那样高性能,零开销抽象,但毫无疑问的是,Boost 的参考价值是无法忽视的,你可以在 Boost 中找到许多非常值得学习和借鉴的实现。如今 TR1 草案已完全融入 C++ 标准当中,没有再过多了解 TR1 标准库的必要。原创 2024-03-21 11:48:56 · 138 阅读 · 0 评论 -
学完Efficient c++ (50-52)
又例如,编译器所带的内存管理器是线程安全的,但如果你的程序是单线程的,你也可以考虑写一个不线程安全的分配器来提高速度。如果你知道特定的某个数据结构往往被一起使用,而你又希望在处理这些数据时将“内存页错误(page faults)”的频率降至最低,那么可以考虑为此数据结构创建一个堆,将它们成簇集中在尽可能少的内存页上。定制 new 和 delete 动态内存的相关信息:分配区块的大小分布,寿命分布,FIFO(先进先出)、LIFO(后进先出)或随机次序的倾向性,不同的分配/归还形态,使用的最大动态分配量等等。原创 2024-03-20 17:58:10 · 1036 阅读 · 0 评论 -
学完Efficient c++ (48-49)
当operator new无法满足某一内存分配需求时,会不断调用一个客户指定的错误处理函数,即所谓的new-handler,直到找到足够内存为止,调用声明于中的set_new_handler可以指定这个函数。由于模板元程序执行于 C++ 编译期,因此可以将一些工作从运行期转移至编译期,这可以帮助我们在编译期时发现一些原本要在运行期时才能察觉的错误,以及得到较小的可执行文件、较短的运行期、较少的内存需求。当然,副作用就是会使编译时间变长。原创 2024-03-19 11:41:09 · 459 阅读 · 0 评论 -
学完Efficient c++ (46-47)
traits classes 可以使我们在编译期就能获取某些类型信息,它被广泛运用于 C++ 标准库中。traits 并不是 C++ 关键字或一个预先定义好的构件:它们是一种技术,也是 C++ 程序员所共同遵守的协议,并要求对用户自定义类型和内置类型表现得一样好。以迭代器为例,标准库中拥有多种不同的迭代器种类,它们各自拥有不同的功用和限制:input_iterator:单向输入迭代器,只能向前移动,一次一步,客户只可读取它所指的东西,而且只能读取一次。(istream_iterators)原创 2024-03-18 10:57:31 · 1099 阅读 · 0 评论 -
【项目设计】基于Httplib和Mysql的视频播放
搭建视频共享播放服务器,可以让所有人通过浏览器访问服务器,实现视频的上传查看,以及管理并播放的功能。主要是完成服务器端的程序业务功能的实现以及前端访问界面的编写,能够支持客户端浏览器针对服务器上的所有视频进行操作。项目名称:视频共享播放系统项目功能:搭建一个共享播放系统,服务器支持用户通过前端浏览器访问服务器,获取展示与观看和操作的界面,最终实现视频的上传以及观看和删改查等基础管理功能。开发环境及工具:Ubuntu 16.04.10 、vim、g++、gdb、makefile、vscode等。原创 2024-03-15 17:40:20 · 1076 阅读 · 0 评论 -
学完Efficient c++ (44-45)
因非类型模板参数而造成的代码膨胀,往往可以消除,做法是以函数参数或类成员变量替换模板参数。因类型模板参数而造成的代码膨胀,往往可以降低,做法是让带有完全相同二进制表述的具现类型共享实现代码。C++ 视模板类的不同具现体为完全不同的的类型(如果用带有base-derived关系的B、D分别具现化同一个template,产生出来的两个具现体并不带有base-derived关系),但在泛型编程中,我们可能需要一个模板类的不同具现体能够相互类型转换。原创 2024-03-15 10:16:50 · 966 阅读 · 0 评论 -
学完Efficient c++ (41-42)
类与模板都支持接口和多态。而对模板参数而言,接口是隐式的,奠基于有效表达式,多态则是通过模板具现化和函数重载解析(function overloading resolution)发生于编译期。加诸于模板参数身上的隐式接口,就像加诸于类对象身上的显式接口“一样真实”,两者都在编译期完成检查,你无法在模板中使用“不支持模板所要求之隐式接口”的对象(代码无法通过编译)。第三种做法是最令人不满意的,如果被调用的是虚函数,上述的明确资格修饰(explicit qualification)会使“虚函数绑定行为”失效。原创 2024-03-14 21:31:27 · 622 阅读 · 0 评论 -
学完Efficient c++ (39-40)
当派生类需要访问基类的protected的成员时或需要重新定义继承而来的virtual函数时,才被迫使用private继承,否则一般使用复合或public继承。由于虚继承会在派生类中额外存储信息来确认成员来自于哪个基类,虚继承通常会付出更多空间和速度的代价,并且由于虚基类的初始化责任是由继承体系中最底层的派生类负责,就导致了派生类必须认知其虚基类并且承担虚基类的初始化责任。因此我们应当遵循以下两个建议:非必要不使用虚继承。如果必须使用虚继承,尽可能避免在虚基类中放置数据。原创 2024-03-13 10:39:23 · 991 阅读 · 1 评论 -
学完Efficient c++ (36-38)
非虚函数和虚函数具有本质上的不同:非虚函数执行的是静态绑定(statically bound,又称前期绑定,early binding),由对象类型本身(称之静态类型)决定要调用的函数;而虚函数执行的是动态绑定(dynamically bound,又称后期绑定,late binding),决定因素不在对象本身,而在于“指向该对象之指针”当初的声明类型(称之动态类型)。原创 2024-03-12 10:26:18 · 521 阅读 · 0 评论 -
学完Efficient c++ (34-35)
我们在条款32讨论了public继承的实际意义,我们在本条款将明确在public继承体系中,不同类型的接口——纯虚函数、虚函数和非虚函数——背后隐藏的设计逻辑。首先需要明确的是,成员函数的接口总是会被继承,而public继承保证了,如果某个函数可施加在父类上,那么他一定能够被施加在子类上。不同类型的函数代表了父类对子类实现过程中不同的期望。将纯虚函数、虚函数区分开的并不是在父类有没有实现——纯虚函数也可以有实现,其二者本质区别在于父类对子类的要求不同,前者在于从编译层面提醒子类主动实现接口,后者则侧重于给予原创 2024-03-11 11:06:34 · 938 阅读 · 0 评论 -
学完Efficient c++ (32-33)
同样的道理,面对矩形和正方形,生活经验告诉我们正方形是特殊的矩形,但这并不意味着在代码中二者可以存在public的继承关系,矩形具有长和宽两个变量,但正方形无法拥有这两个变量——没有语法层面可以保证二者永远相等,那就不要用public继承。之前我们了解过 C++ 名称查找法则,这在继承体系中也是类似的,当我们在派生类中使用到一个名字时,编译器会优先查找派生类覆盖的作用域,如果没找到,再去查找基类的作用域,最后再查找全局作用域。,如果不是,则无论生活经验是什么,都不能视作”is-a”的关系。原创 2024-03-10 18:43:36 · 257 阅读 · 0 评论 -
学完Efficient c++ (28-31)
避免返回 handles(包括引用、指针、迭代器)指向对象内部。遵循这个条款可增加封装性,使得const成员函数的行为符合常量性,并将发生 “空悬句柄” 的可能性降到最低。当异常被抛出时,带有异常安全性的函数会:不泄漏任何资源。不允许数据败坏。nline函数无法随着程序库的升级而升级,如果func函数是程序库的一个inline函数,客户将func函数编进其程序中,一旦程序设计者改变func函数,所有的func的客户端程序必须重新编译。而如果func函数是一个non-inline函数。一旦它有修改,客户原创 2024-03-09 20:03:49 · 818 阅读 · 0 评论 -
学完Efficient c++ (26-27)
当变量定义出现时,程序需要承受其构造成本;当变量离开其作用域时,程序需要承受其析构成本。因此,避免不必要的变量定义,以及延后变量定义式直到你确实需要它(甚至应该尝试延后变量的定义直到能够给它初值实参为止)。// 效率低// 效率高对于循环中变量的定义,我们一般有两种做法:Widget w;i < n;++i) {w = 取决于 i 的某个值;...这种做法产生的开销:1 个构造函数 + 1 个析构函数 + n 个赋值操作。i < n;++i) {原创 2024-03-08 10:53:46 · 558 阅读 · 0 评论 -
学完Efficient c++ (24-25)
这个条款告诉了我们。作者想给我们提个醒,如果我们在使用操作符时我们首先说明:如果一个操作符是成员函数,那么它的。现在我们有一个Rational类,并且它可以和int首先简单讲解一下当操作符被重载成员函数时,第一个操作数特殊的身份。操作符一旦被设计为成员函数,它在被使用时的特殊性就显现出来了——单从表达式你无法直接看出,不是吗?例如下方的有理数类重载的操作符”+”,当我们在调用时,调用操作符函数的对象并没有直接显示在代码中——这个操作符的this指针指向x还是y呢?作为成员函数的操作符的第一个隐形参数”原创 2024-03-07 10:38:20 · 803 阅读 · 0 评论 -
学完Efficient c++ (21-23)
一个量化某成员封装性好坏的简单方法是:看类内有多少(public或protected)函数直接访问到了这个成员,这样的函数越多,该成员的封装性就越差——该成员的改动对类外代码的影响就可能越大。回到我们的问题,高颗粒度函数在设计之时,设计者的本意就是。又或者采用不同namespace来明确责任,将不同的高颗粒度函数和浏览器类纳入不同namespace和头文件,当我们使用不同功能时就可以include不同的头文件,而不用在面对cache的需求时不可避免的将cookies的工具函数包含进来,降低编译依存性。原创 2024-03-05 10:35:31 · 644 阅读 · 0 评论 -
学完Efficient c++ (18-20)
当使用按值传参时,程序会调用对象的拷贝构造函数构建一个在函数内作用的局部对象,涉及大量参数的复制,这些副本大多是没有必要的,这个过程的开销可能会较为昂贵。对于任何用户自定义类型,使用按常引用传参是较为推荐的(因为没有任何新对象被创建,这种传参方式不会调用任何构造函数或析构函数,所以效率比按值传参高得多。)对于内置类型、STL的迭代器和函数对象,使用按值传参是比较合适的。原创 2024-03-04 10:26:33 · 610 阅读 · 0 评论 -
学完Efficient c++ (14-17)
每一次复制对象就使引用计数+1,每一个对象离开定义域就调用析构函数使引用计数-1,直到引用计数为0就彻底销毁资源。当我们在设计自己的资源管理类时,也要考虑在提供对原始资源的访问时,是使用显式访问还是隐式访问的方法,还是两者皆可。,例如在一个对象中有一个指针,那么在复制这个对象时就不能只复制指针,也要复制指针所指向的数据。的行为类似,永远保持只有一个对象拥有对资源的管理权,当需要复制对象时转移资源的管理权。我们应该永远保持这样的思考:当一个RAII对象被复制,会发生什么事?原创 2024-03-03 14:35:32 · 412 阅读 · 0 评论 -
学完Efficient c++ (13) + 智能指针详解和实现
内存只是众多被管理的资源之一,对待其他常见的资源如互斥锁、文件描述器、数据库连接等时,我们要遵循同一原则——如果你不再使用它们,确保将他们还给系统。1. C++ 98 中产生了第一个智能指针auto_ptr.2. C++ boost给出了更实用的scoped_ptr和shared_ptr和weak_ptr.3. C++ TR1,引入了shared_ptr等。不过注意的是TR1并不是标准版。4. C++ 11,引入了unique_ptr和shared_ptr和weak_ptr。需要注意的是unique_ptr原创 2024-03-02 11:34:49 · 532 阅读 · 0 评论 -
学完Efficient c++ (11-12)
除此之外,拷贝构造函数和拷贝赋值操作符,他们两个中任意一个不要去调用另一个,这虽然看上去是一个避免代码重复好方法,但是是荒谬的。那么对于管理一定资源的对象重载的operator = 中,一定要对是不是自我赋值格外小心并且增加预判,因为无论是深拷贝还是资源所有权的转移,原先的内存或所有权一定会被清空才能被赋值,如果不加处理,这套逻辑被用在自我赋值上会发生——先把自己的资源给释放掉了,然后又把已释放掉的资源赋给了自己——出错了。如果你忘记处理,编译器也不会报错。指向的是相同的对象,就会导致访问到已删除的数据。原创 2024-03-01 11:11:27 · 585 阅读 · 1 评论 -
学完Efficient c++ (08-10)
如果析构函数执行期间某个时刻抛出了异常,就说明抛出异常后的代码无法再继续执行,这是一个非常危险的举动——因为析构函数往往是为类对象兜底的,甚至是在该对象其他地方出现任何异常的时候,析构函数也有可能会被调用来给程序擦屁股。在多态环境中,我们需要重新理解构造函数和析构函数的意义(在创建派生类对象时,基类的构造函数永远会早于派生类的构造函数被调用,而基类的析构函数永远会晚于派生类的析构函数被调用),这两个函数在执行过程中,涉及到了对象类型从基类到子类,再从子类到基类的转变。原创 2024-02-29 10:59:09 · 453 阅读 · 1 评论 -
学完Efficient c++ (06-07)
如果一个类有多态的内涵,那么几乎不可避免的会有基类的指针(或引用)指向子类对象,因为非虚函数没有动态类型,所以如果基类的析构函数不是虚函数,那么在基类指针析构时会直接调用基类的析构函数,造成子类对象仅仅析构了基类的那一部分,有内存泄漏的风险。但若此时从该基类中派生出新的类,会发生报错,这是因为派生类的析构函数中将会调用基类中的纯虚析构函数,而编译器无法找到基类的析构函数的实现。虚析构函数的运作方式是:最深层派生的那个类的析构函数最先被调用,然后是其上的基类的析构函数被依次调用。原创 2024-02-28 10:58:42 · 412 阅读 · 0 评论 -
学完Efficient c++ (05)
编译器会主动为你编写的任何类声明一个拷贝构造函数、拷贝复制操作符和一个析构函数,同时如果你没有声明任何构造函数,编译器也会为你声明一个default版本的拷贝构造函数,这些函数都是public且inline的。对于拷贝构造函数,你要考虑到类内成员有没有深拷贝的需求,如果有的话就需要自己编写拷贝构造函数/操作符,而不是把这件事情交给编译器来做。对于拷贝构造函数,如果类内有引用成员或const成员,你需要自己定义拷贝行为,因为编译器替你实现的拷贝行为在上述两个场景很有可能是有问题的。原创 2024-02-27 16:11:58 · 245 阅读 · 0 评论 -
学完Efficient c++ (04)
对于类中的成员变量而言,需要通过构造函数进行初始化,确保每一个构造函数都将对象的每一个成员初始化。对象的成员变量的初始化发生在进入构造函数之前,在构造函数内使用“=”是给成员变量赋值,而不是初始化,初始化发生在成员变量的default构造函数被自动调用时。(基于赋值的构造函数,首先调用default构造函数为成员变量设初值,然后再对它们赋新值)使用构造函数成员初始化列表(基于初值列的构造函数,对成员变量设实参,每个成员变量以实参为初值进行copy构造,效率更高;对于内置类型的成员变量,两个方法效率相同)原创 2024-02-27 13:52:20 · 238 阅读 · 0 评论 -
学完Efficient c++ (01-03)
编译器对待const对象的态度通常是 bitwise constness(const成员函数不能修改对象内任何非静态成员变量),而我们在编写程序时通常采用 logical constness,这就意味着,在确保客户端不会察觉的情况下,我们认为const对象中的某些成员变量应当是允许被改变的,使用关键字。需要注意的是,反向做法:令const版本调用non-const版本以避免重复——并不被建议,一般而言const版本的限制比non-const版本的限制更多,因此这样做会带来风险。原创 2024-02-26 21:48:49 · 667 阅读 · 1 评论 -
【项目设计】基于Epoll(IO多路转接)和httplib的boost库搜索引擎
关于项目总结,主要是针对项目的扩展1. 建立整站搜索我们搜索的内容是在boost库下的doc目录下的html文档,你可以将这个库建立搜索,也可以将所有的版本,但是成本是很高的,对单个版本的整站搜索还是可以完成的,取决于你服务器的配置。2. 设计一个在线更新的方案,信号,爬虫,完成整个服务器的设计我们在获取数据源的时候,是我们手动下载的,你可以学习一下爬虫,写个简单的爬虫程序。采用信号的方式去定期的爬取。3. 不使用组件,而是自己设计一下对应的各种方案。原创 2023-12-31 20:33:27 · 1044 阅读 · 1 评论 -
linux的getcwd()和chdir()函数
登录时,工作目录设置为起始目录(home directory),该起始目录从口令文件(通常是/etc/passwd)中的相应用户的登录项中取得。口令文件中的登录项由7个以冒号分隔的字段组成,依次是:登录名、加密口令、数字用户ID、数字组ID、注释字段、起始目录以及shell程序。功能:getcwd()会将当前工作目录的绝对路径复制到参数buffer所指的内存空间中,参数size为buf的空间大小。函数原型:char *getcwd(char *buf, size_t size);功能:改变当前工作目录。原创 2023-12-14 16:55:50 · 414 阅读 · 1 评论 -
c执行linux命令的函数:popen
函数说明:popen()会调用fork()产生子进程,然后从子进程中调用/bin/sh -c 来执行参数command 的指令。此外,所有使用文件指针(FILE*)操作的函数也都可以使用,除了fclose()以外,用pclose()来关闭。原创 2023-12-14 16:52:31 · 102 阅读 · 1 评论 -
fflush与fsync的关系(语言级缓冲区与内核级缓冲区)
对于输出设备或磁盘文件,fflush只能保证数据到达内核缓冲区,并不能保证数据到达物理设备, 因此应该在调用fflush后,调用fsync(fileno(stream)),确保数据存入磁盘。fflush是libc.a中提供的方法,是用来将流中未写的数据传送到内核。linux底层操作,属于内核调用, 涉及到进程上下文的切换,即用户态到核心态的转换,这是个比较消耗性能的操作。c库缓冲-----fflush--------->内核缓冲--------fsync(刷盘)----->磁盘。原创 2023-12-14 16:46:13 · 108 阅读 · 1 评论 -
基于红黑树实现stl的map和set容器
【代码】基于红黑树实现stl的map和set容器。原创 2023-11-15 20:54:55 · 35 阅读 · 1 评论 -
匿名管道和命名管道的概述理解和c++实现——进程间通信
匿名管道和命名管道的概述理解和c++实现——进程间通信。原创 2023-11-15 12:09:04 · 96 阅读 · 1 评论 -
RBTree(红黑树)的递归和非递归插入
算法导论》中的红⿊树《算法导论》中的红⿊树1.每个节点或者是红⾊的,或者是⿊⾊的2.根节点是⿊⾊的3.每⼀个叶⼦节点(最后的空节点)是⿊⾊的4.如果⼀个节点是红⾊的,那么他的孩⼦节点都是⿊⾊的5.从任意⼀个节点到叶⼦节点,经过的⿊⾊节点是⼀样的红黑树的最长路径中节点数不会超过最短路径节点个数的两倍。最长路径:一黑一红间隔最短路径:全黑路径:root->NULL。原创 2023-11-13 21:33:57 · 72 阅读 · 0 评论 -
AVL树的递归和非递归插入、删除、查找等操作的C++实现(考虑平衡因子和树的高度)
AVL树根据平衡特性和二叉搜索树的特性递归实现插入、删除。AVL树的非递归实现插入和查找(根据平衡因子的判断)原创 2023-11-10 16:07:38 · 78 阅读 · 1 评论 -
进程替换,exec系列函数使用
进程替换,exec系列函数使用进程替换就是指进程不变(进程的pcb,进程地址空间不变),仅仅替换当前进程的代码和数据的技术(新程序的替换旧进程的),叫做进程的程序替换,这样就好像子进程执行了一个全新的程序。原创 2023-11-01 12:09:31 · 60 阅读 · 1 评论