
C/C++
文章平均质量分 70
werflychen
曾经在腾讯百度从事过后台开发,现在一个券商从事后台开发,chenwenh@foxmail.com
展开
-
unique_ptr实现Impl模式时遇到的问题分析
背景对于类的设计与定义,我们习惯上使用“指向实现的指针”, 或者叫PImpl。例如下面的类:// widget.h(接口)class widget { // 公开成员private: struct impl; // 实现类的前置声明 impl* ptr;};// widget.cpp(实现)struct widget::impl { // 实现细节...原创 2019-08-07 10:43:04 · 2052 阅读 · 1 评论 -
哈希桶的预分配内存的实现形式
之前在书本中使用过的hashtable的时候,总体思想是使用一大片内存,然后把key值hash成一个int,找到对应的内存的结构的位置,然后找到相应的数据。常用的解决冲突的方式是,需要进行拉链,再new一个新结点来表示数据。这是一种实现形式,逻辑上没有什么问题。总体方案如下图所示 存在问题:大部分情况下,都需要通过动态分配内存的方式进行拉链。而对于类似共享内存,或者是堆内存,预...原创 2018-10-10 11:05:26 · 997 阅读 · 0 评论 -
C语言结构体中解决变长数据结构连续内存分配的定义的一种方法(char data[0])
最近项目中,有一个业务场景需要使用一个变长数据结构。而且需要使用连续内存。例如这个场景,我定义一个字段,它来表示DB结构的某个列,如下所示:struct Col_v0 { int type; int len; char data[100];};一般来说,我们可以简单的定义成这样。直接用一个定长的结构体来表示。又有人或者有疑问,要表示一个变长的,不是可以直接用...原创 2018-10-14 22:00:02 · 2165 阅读 · 3 评论 -
磁盘IO效率的简单总结
最近一段时间的项目进入阶段性收尾,项目中由于遇到了数据需要落地的场景,因此,便需要好好整理一下。这里从几个问题开始:1、对于传统的机械硬盘,如何让写磁盘速度更快?如何了解自己是否已经达到最优?2、多进程写文件的时候,如何保证文件有序?3、只有一个磁盘,多进程写文件的时候,是同时写到一个文件更快,还是多个进程写到多个文件,总体IO效率更高?4、在某些对数据严格要求安全的场景下,有什么...原创 2018-09-29 11:32:13 · 6271 阅读 · 1 评论 -
二分搜索问题总结
最近工作中遇到了二分搜索问题。它是计算机课程中最基础的算法,这是我们在顺序查找时,最直接的一种提速的普遍性算法了,能够将一个顺序的查找的时间复杂度,从O(n)提升到了O(logn),这是质变的算法。首先我们来看一下一个经典的二分搜索算法:int BinarySearch(vector<int>& vec_arr, int target) { int left ...原创 2018-10-02 08:43:57 · 425 阅读 · 0 评论 -
函数返回值的优化技术(RVO和右值引用)
我们先来看一段例子,一个简单的函数返回值场景#include <iostream>using namespace std;class Moveable {public: Moveable():h(new int(3)) { cout << "construct " << endl; } ~Moveabl...原创 2018-09-06 23:42:49 · 2471 阅读 · 0 评论 -
整形溢出的总结
最近在项目中需要做一个算术运算比较问题,涉及到一个比较的溢出问题。可以简单的抽象成一个示例如下:int a = -100;unsigned b = 100;if (a < b) { cout << "a(-100) < b(100)" << endl;} else { cout << "a(-100) > b(...原创 2018-09-16 23:20:56 · 3883 阅读 · 0 评论 -
压力测试的一点思考
最后工作中的项目,接近上线了,做了个完整的压力测试过程,对于压力测试,整个项目下来,有些自己的理解,这里简单总结如下:压测的目的1、检查系统是否要求业务需求,拿到系统的一些性能指标。一般情况下,例如峰值是1W/s的系统,压测的时候,需要能扛上2W/s基本就能满足要求(特殊业务可能另作评估)。并且输出压测报告,拿到一个对系统的量化指标,做到一切心中有数。2、发现系统存在的问题。很...原创 2018-09-03 23:50:41 · 253 阅读 · 0 评论 -
二分搜索常用变种(N个相同目标,寻找第一个或最后一个目标元素)leetcode 278
/* * 二分搜索的一个变种,找到第一个等于target的下标 */ int binarySearchFirst(vector<int>& nums, int target) { if (nums.empty()) { return -1; } ...原创 2018-09-02 22:26:41 · 185 阅读 · 0 评论 -
leetcode 旋转数组
这个旋转数组,看似挺简单,但真正想要不用调试,直接写出通过的,基本功还是要特别扎实,记自己通过的三种方法class Solution {public: /* solution 1:直接用了n个辅助空间,空间复杂度过高 */ void rotate(vector<int>& nums, int k) { vector<int> r...原创 2018-08-24 23:01:55 · 395 阅读 · 0 评论 -
linux vim如何强制输出TAB(ctrl + v + i不生效)
记一个小技术,在LINUX下使用VIM时,经常是把TAB替换成了四个空格。而写makefile的时候,经常需要使用TAB才能输入命令。这时候需要强制VIM输出TAB,而不是四个空格。 方案1: 最原始的办法可以是这样,设置set noexpandtab,把这个替换去掉。 方案2: 直接使用ctrl + v + i,(网上...原创 2018-08-03 14:24:20 · 2212 阅读 · 0 评论 -
坑爹的if语句
前两天的时候,自己在修改代码的时候,自己感觉对调试比较有心得体会了。但遇到一个问题,总在一个函数中返回了false,明明条件就是不应该返回。修改前的示例代码如下: string topic = "topic is not empty";if (topic.empty()) return false;我想对这行代码加一个日志打印,示例如下:s...原创 2018-07-21 17:48:50 · 203 阅读 · 0 评论 -
vector bool 引发的如何发现问题的思考
前段时间,在项目开发过程之中,自己遇到了一个奇怪的问题。使用了vector<bool>,而将vector<bool>的元素值,作为引用值去传参数的时候,报了个莫名其妙的错。当时因为在赶进度,觉得根据自己的理解,可能一时半会搞不定,就没有深纠,另外,觉得这可能会是一个好问题,就先把这个问题记下来,先不管,尝试用其他办法先把项目实现先搞定,等主要工作完成之后,再尝试回过头来安排...原创 2018-07-07 09:56:54 · 629 阅读 · 0 评论 -
为什么中断信号SIGINT处理函数不生效?
问题背景一个测试可代码编的可执行程序中,执行开始之后,然后按下Ctrl-C,中断程序运行,看core文件,程序是跑到了一个第三方的库里面coredump了。问题初步分析正常的怀疑,就是自己没有安装中断处理函数,导致出问题。那么步骤1:尝试自己安装中断处理函数。自己的代码是一个zmq的poll阻塞式调用。在ZMQ系统开始初始化之前,安装了一个中断处理函数。函数代码大致如下:中断信号处理函数expan...原创 2018-06-28 16:53:57 · 1470 阅读 · 1 评论 -
全局变量链接顺序问题
背景问题最近同事项目中遇到一个问题,就是在main函数未启动之前,就出现崩溃。具体现场情况大致是使用了一个map,但这个map的insert操作直接导致崩溃。最终定位的原因,是map的定义是放到了另一个编绎单元之中,而使用map的时候,该map对象还未进行初始化。这是全局变量的初始化顺序问题,即是用到某个变量的时候,它其实还未初始化。问题简化知识点:1、全局变量的初始化,是在mai...原创 2018-07-16 20:46:44 · 817 阅读 · 0 评论 -
动态共享库引发的double free错误的分析
问题背景项目中遇到了这么个场景:项目中,所有文件可以生成一个动态链接库A.so场景1:A.so 假设由N个.o生成,不妨假设由a.o,b.o生成。如果将main.cpp -> main.omain.o, a.o, b.o -> main_bin,运行./main_bin,运行正常。 场景2:将A.so、main.cpp,两个一起生成一个可执行程序即是main.cpp -> ma...原创 2018-07-02 21:41:42 · 2999 阅读 · 3 评论 -
如何使用protobuf的反射机制遍历所有已设置的FieldDescriptor*
背景在项目开发中,由于需要使用到一个protobuf的API, 用于对不同Message的比较过程中,设置浮点数比较精度的API,MessageDifferencer::SetFractionAndMargin(const FieldDescriptor * field, double fraction, double margin),需要传入一个Message的FieldDescri...原创 2018-07-09 12:17:17 · 8619 阅读 · 5 评论 -
静态链接时被依赖的库放到后面的原因?
接着前一篇文章动态共享库引发的double free错误的分析,分析到的共享库的double free问题,这里接着谈一下我们经常在链接的过程中,经常处理的一个错误,就是被依赖的库,通过需要放到依赖库的后面,但之前一直不太清楚原因是什么。这里看到有位网友,把整个流程图画出来了,这里引用一下他的文章:《浅析静态库链接原理》,这里引用了他的流程图:主要原因是:1、对于静态依赖,其实就是.a文件中,依次...原创 2018-07-08 20:23:26 · 815 阅读 · 0 评论 -
mysql innodb索引结构的理解
从几个“经验”做法问题开始:1、建索引的时候,建议使用一个id字段作为主键,并递增的插入,这样效率更高。2、为什么索引查询的时候,会有前缀匹配的约束?开始的时候抛出这两个问题,我们先了解完innodb的索引的数据结构,再回来看这两个问题是不是更清晰了。innodb的数据与主键索引是如何组织B树与B+树的基本原理mysql的索引通过B+树来进行组织。为什么是B+树?这先简单回...原创 2018-10-21 23:54:23 · 426 阅读 · 0 评论 -
leveldb设计思想学习总结
leveldb的价值每一类组件,都有它特定擅长的应用场景。在leveldb出世之前,我们对于nosql下的kv存储,我们有redis方案存储。然而redis数据存储的上限,即是机器内存。内存在目前阶段,算是比较昂贵。而leveldb的出现,提供了一个可以以机器磁盘为容量上限,支持持久化的写操作的同时,做到写速度较快,读速度也不慢的一个解决方案。leveldb如何解决问题leveldb面对的问...原创 2019-07-31 21:29:56 · 409 阅读 · 0 评论 -
c++中函数返回时的RVO机制和std::move的理解
常见问题RVO和std::move都能减少对象拷贝时的开销,那他们到底是什么与什么的关系叫?talk is cheap, show me the code!如下代码所示:test_1.cpp场景一【函数返回非RVO】class Obj {public: Obj() { printf("construct \n"); } ~Obj() {...原创 2019-07-28 09:26:21 · 1390 阅读 · 2 评论 -
fork生成子进程与执行exec子进程的区别
背景项目中想使用多进程的模式。一个控制进程,加上N个工作进程。即是master+worker进程的模式,与nginx的进程模式类似的思路。master创建并管理worker进程,而且他们之间需要能够进行通信。设计思路如下图所示:遇到问题如何创建woker进程linux系统下,创建进程,肯定使用fork来做系统调用。然后fork之后,我们通过ps看到子进程名称也是master,从使用角度来...原创 2019-07-17 12:15:35 · 1446 阅读 · 0 评论 -
fork多线程中需要注意的问题
单线程场景对于fork系统调用,我们知道是linux下创建子进程的一种方式。fork调用一次,对于程序看来,是“返回两次”。这里其实理解为fork调用中,已经创建出了子进程,父子进程分别分从fork调用中返回。父进程需要知道子进程的进程ID,所以返回值大于0的是父进程,而子进程返回0即可,子进程可以通过getpid获取自身进程ID和getppid获取父进程ID。多线程场景对于多线程场景中,例...原创 2019-07-16 23:46:02 · 503 阅读 · 0 评论 -
STL使用时的一个常见错误(拷贝构造函数)
背景最近在协助同事定位问题的时候,发现一个有趣的问题。使用std::map的insert函数插入的时候,总是报了一个莫名的错误。std::map<std::string, T> map_data;而 T的类型,则是一个第三方的类类型。而看到的报错,则是完全没有头绪。定位说实话,如果再来一次,这种问题我来看错误,我是肯定想不到是这种原因导致的,因为错误信息中完全找不到跟问题相关的提...原创 2019-06-19 16:54:11 · 2509 阅读 · 3 评论 -
库冲突错误warning: libstdc++.so.5 needed by xxx, may conflict with libstdc++.so.6
背景在开发项目的时候,链接的时候,遇到错误warning: libstdc++.so.5, needed by /oracle/product/10.2.0/db_1/lib/libocci.so, may conflict with libstdc++.so.6,起初没有太留意,编绎还是能正确编绎,也能单独运行。问题在某个库进行集成之后,在调用OCCI库的API的时候,出现了莫名的失败。主...原创 2019-05-13 21:10:25 · 4036 阅读 · 0 评论 -
gcc新旧版本ABI在项目中兼容性问题
ABI这里与我们常用的API的概念一起拿出来对比认识。API全称:Application Program InterfaceAn API defines the interfaces by which one piece of software communicates with another at the source level.ABI全称:Application Binary ...原创 2019-04-10 12:16:28 · 5738 阅读 · 2 评论 -
异步业务系统的一个常用实现模式
业务场景一个系统,依赖很多外部系统的数据。对于一个请求过来,需要查询N个外部系统的数据,等全部数据拿到之后,做数据处理完之后,返回给请求端。如果依赖系统太长时间未返回,我们必须有一个超时响应机制返回给客户端。简单方案最简单的方案,就是通过同步的方式。一个客户端请求过来,假如依赖3个接口,则同步顺序的去请求三个接口,send1, recv1, send2, recv2, send3, recv...原创 2019-03-11 19:32:38 · 450 阅读 · 1 评论 -
tcp挥手时的异常情况(SIGPIPE、shutdown vs close操作)
正常的TCP端的四次挥手问题1:如果只是关闭了一端,另一端还能发数据么我们知道,TCP是一个双全工协议,从协议层面,我们了解到,如果client发了FIN包给服务端,在收到ACK之后,状态切换成FIN_WAIT2。此时,从协议层面,只是关闭了client->server这个方向的数据传输。而server->client端,则可以继续往client端发数据。可以参考《tcp/ip详...原创 2019-02-20 10:25:24 · 862 阅读 · 0 评论 -
动态链接库链接参数不要写成静态链接形式
背景动态链接库常用写法:动态链接库的路径在/usr/local目录,动态链接库的名称为libtest.so,我们在链接的时候,一般使用g++ -o test_bin main.o -L$(library_path) -ltest类似这种形式来指定目标文件需要的动态链接库。静态链接库的写法如下:例如静态链接库放到/usr/local/libstatic.a,我们在链接的时候,一般使用g...原创 2018-12-03 19:23:45 · 488 阅读 · 2 评论 -
redis重新分片及迁移技术
redis分片分片场景在业务量相对较小的时候,可以将所有数据都存到一台机器上,只使用redis单机模式,不存在分片问题。如果业务的数据量超过一台物理机器的内存大小时,则会面对扩展问题,需要多台机器去存数据,此时,需要使用到redis的分片技术。如何分片redis通过分slot的方式进行分片。例如有A、B、C三台机器组成的一个集群。对于集群里面的节点而言,三者会全部覆盖16384个slots...原创 2018-11-25 21:43:31 · 2388 阅读 · 4 评论 -
redis的有序集的实现原理
有序集从用户的角度来看,有序集,它首先是一个集合,并且,他可以是顺序的。按照redis提供的命令来看,他可以通过指定key来查找成员,另一方面,可以通过指定score分数,来返回一个还区间的有序成员。如下图所示:哈希方案如果使用redis中的字典基本数据结构,从逻辑上讲,是能满足需求,在查找效率方面,能达到近O(1)时间复杂度。但如果要返回区间的时候,则需要进行内存排序操作,这个场景效率...原创 2018-11-18 23:35:38 · 1092 阅读 · 0 评论 -
一个分布式限流系统的设计思路
问题背景今天在参与面试的时候,候选人提到了一个他们项目做的一个项目中使用的限制系统的设计。大致思路如下,通过一个配置中心去获取每台机器的配额,然后本地做限流。当时就被挑战了这个思路,如果其他机器挂了,如何快速感知?马上就没答上来了。基于这个话题,今天想来简单分析一下,一个限流系统的设计思路。基本算法1、先讨论最简单的场景,单台机器,用什么方式来限制流量?通知一个非常简单的做法,暂且叫它为时间...原创 2018-11-13 00:32:05 · 1095 阅读 · 1 评论 -
为什么有些类型无法使用memset初始化?
基本经验我们知道,对于这个问题,一般的开发经验是一些基本数据类型的,像int, char, double之类的构造的简单struct类型,我们在C语言中,一般使用memset来对一片内存进行初始化。而另一个经验又是,有些类型,我们不能使用memset进行初始化,例如:string, vector之类的stl结构,或者是一些自定义的类型比较复杂的,例如有多态性质的类定义。什么样的类可以使用mem...原创 2018-11-11 22:23:15 · 4346 阅读 · 5 评论 -
不同容器(GCC7.1与GCC4.8.5)运行相同代码导致效率巨大差别的案件追踪(第二篇)
localtime函数最权威的使用手册不是百度,而是man,在man里面提到与与时区相关。再通过谷歌找到一个前人对localtime进行调优的博客How setting the TZ environment variable avoids thousands of system calls,详细信息可以参考里面的内容描述,这里不赘述。原因解释按照前人得出来的结论,localtime里面,如...原创 2018-11-11 21:09:29 · 1066 阅读 · 0 评论 -
不同容器(GCC7.1与GCC4.8.5)运行相同代码导致效率巨大差别的案件追踪(第一篇)
背景之前对项目中日志组件做了一轮优化测试之后,在GCC4.8.5下,跑一个测试案例(写100万条日志,每条1K字节),能跑到4.2S左右的耗时。而今天发现了一个奇怪的现象,同样的代码,居然在GCC7.1的容器下,跑出了7.5S左右的水平。百思不得其解!不同的容器能跑出相差50%左右的时间出来。而且是更新版本的容器,性能差了将近一倍,无论如何都无法解释。后面简称安装GCC4.8.5的是A容器,安...原创 2018-11-08 00:09:17 · 2127 阅读 · 0 评论 -
多进程写同一个日志并发问题分析
背景问题在优化日志组件项目中有如下场景:两个进程,A、B进程往同一个文件写日志的时候,使用C语言的库函数写,fopen文件追加方式打开, fwrite等。如果每一次写的时候都强制fflush操作,则写的时序是正常的。如果不是每次fflush操作的时候,则会出现写入日志的时候的时序问题,即是A进程的一条日志没打完,B进程的日志中间插进来了。问题分析原子性系统调用先从最基本的系统调用说起...原创 2018-10-26 23:14:57 · 6284 阅读 · 4 评论 -
makefile中的命令与普通的shell命令的区别
问题背景今天在makefile中,遇到一个场景,依赖一个目标,需要cd到其他文件夹里面执行一个操作。简单来说,可以描述成这样: lbm_mtl_server_mock.so这个目标的生成,我需要去到相关的目录去执行一个make操作。注:这里的LBM_MTL_SERVER_DIR=/workspace/branches/linux/pb_lbm/lbm_mtl_server然后,就遇到了一个问...原创 2018-06-13 16:53:03 · 431 阅读 · 0 评论 -
C++的一个编绎错误引发的问题分析 expected unqualified-id before ‘(’ token
今天在编绎一段代码的时候,忽然间,出现了一个比较诡异的错误,长这个样子【expected unqualified-id before ‘(’ token】,这里上个图可能会清楚一些。报错位置在X_pb.h文件的317行(X_pb.h这个文件是protobuf自动生成的)。第一反应即是这个文件是自动生成的,怎么可能会有问题?别急,我们一点点来看。找到这个文件的317行。眼睛瞪到最圆的程度,盯...原创 2018-06-11 21:43:12 · 136891 阅读 · 13 评论 -
使用valgrind检查内存泄露
因为之前所在公司,写的代码都不允许使用动态分配内存,直接使用静态预先分配方式,所以根本不存在内存泄露的问题。现在新公司里面都原创 2014-07-08 17:35:35 · 1187 阅读 · 0 评论 -
hiredis的一些使用心得
最近公司的一个后台项目使用的cache模块,由于使用的是公司内部开发的一套分布式的系统,系统由于年代比较久远,也已经没有人员进行维护了,出了问题便无人懂得如何维护,也没有相应的文档,便最近想办法使用一个新的cache模块进行替换。 开源的cache服务中,当前属redis比较流行,支持的数据类型也比较丰富,是开源项目中比较成熟的方案,公司内部也有其他团队已经选择了该方案。因此便决原创 2015-03-25 20:17:58 · 11025 阅读 · 0 评论