实习/秋招时按自己需求总结的知识点,内容并不十分详细,建议选择性阅读。

C++基础

如何在main函数之前调用函数

  • C语言,采用__attribute__关键字,void f()attribute((constructor))
  • C++,构造函数构造的全局对象

static和const的作用和区别

static
  • 修饰变量,放在静态存储区,调用时返回的是上次改变之后的结果
  • 修饰函数,避免同名问题
  • 修饰成员变量,多个类的对象共有,且可在对象呗构造出来之前使用
  • 修饰成员函数,多个类的对象共有,且只能访问静态成员变量
const
  • 修饰变量,使其不可变
  • 修饰引用,避免拷贝
  • 修饰指针,常量指针,指针不可变;指向常量的指针,常量不可变
  • 修饰成员函数,函数内部不可修改成员变量

指针和引用的区别

  • 指针初始化可为null,引用必须绑定对象
  • sizeof§返回的是指针字节大小,sizeof(引用)返回的是绑定对象的字节大小
  • 指针有自己的空间,而引用只是别名

野指针

  • 指向非法内存的指针
  • 指向一个被删除对象的指针

new和malloc的区别

  • new是按类型分配的,而malloc是按字节数的大小分配的;
  • new返回的是特定的类型,而malloc返回的是void*,因此使用时需转换,如下:
char *p = new int[12];
char *p = (char*)malloc(sizeof(char)*12);
  • new的对象用delete删除,malloc的对象用free释放
  • new不仅会分配内存,还会执行构造函数
  • new是一个操作符,可以重载,而malloc是一个库函数
  • new会调用构造函数

malloc

malloc用于动态分配内存,为了避免内存碎片以及降低系统调用的开销,malloc采用内存池的方式,先申请大块内存作为堆区,然后将堆区分成若干块,以块作为内存分配的基本单位
malloc在申请内存时,若申请的大小小于128k,则采用brk系统调用,大于128k时,采用mmap系统调用

volatile关键字

百度释义:

易变的; 无定性的; 无常性的; 可能急剧波动的; 不稳定的; 易恶化的; 易挥发的; 易发散的;

指那些会被编译器之外的,如操作系统,硬件或其他线程修改的变量,被修饰为volatile的变量不会被编译器优化,所谓的优化是指:

编译器读取一个变量时,会定位到这个变量的地址里读,下次再读时,就直接取出这个值,而不用再访问地址

但是被volatile修饰的变量,编译器每次读取都会从变量所在的地址里读(这是因为之前读过的变量可能会被操作系统/硬件/其他线程篡改)

extern关键字

https://blog.csdn.net/weixin_37569048/article/details/83378642
修饰变量,在a.c中定义,如int i=2;在b.c中使用,需

extern int i;

extern “C”

目的是为了C++按照C的方式编译,从而实现C和C++的混合编程
比如用C语言开发了一个DLL库并导出,为了能够让C++也能调用,需要在C++中使用 extern “C” 来强制编译器不要修改函数名
在C++中:

// cpp_test.h
# ifndef CPP_TEST_H_
#define CPP_TEST_H_#ifdef __cplusplus
extern "C" {
#endif#ifdef __cplusplus
}
#endif
#endif
  • C++的运算符重载
    可以理解为编译时多态,如对于函数
    void f(int i, int i)
    编译器会将其编译为
    f_int_int
    即函数名+参数类型的组合,从而实现运算符重载,而C语言是不会做这个修改的,因此按C++编译的函数,无法在源C文件中找到对应的目标文件,从而报错

final和override关键字

C++11中,在类后面加final关键字使其不可被继承:

class A final { // 不可被继承};

使用override关键字显示指明重载了某一函数

实现一个不能被继承的类
// 初始版,不能用于其他用途
class FinalClassBad {private:    // 私有构造,无法被访问,因此不能被继承FinalClassBad() {}~FinalClassBad(){}
};
// 进阶版,采用静态方法,用的是单例模式,无法在堆上构造
class FinalClassStatic {
public:static FinalClassStatic* Construct(int n) {FinalClassStatic * fcs = new FinalClassStatic();fcs->n = n;return fcs;}static FinalClassStatic* Deconstruct(FinalClassStatic * a) {delete a;a = nullptr;}int n;
private:FinalClassStatic(){}~FinalClassStatic(){}
};FinalClassStatic *fcs = FinalClassStatic::Construct(4);
FinalClassStatic::Deconstruct(fcs);
// 最终版
template< typename T>
class Base {
friend T;   // 友元,可访问私有函数
private:T() {}~T(){}
};// 该类不能被继承
class FinalClass : virtual Base<FinalClass> {   public:FinalClass(){}~FinalCalss(){}
};int main()
{FinalClass *fc = new FinalClass();FinalCalss fc2;
}

#define

宏展开发生在预编译期
有坑,如:

#define MIN(A,B) ((A) <= (B) ? (A) : (B))
调用
least = MIN(*p++, b);
p会被自增两次

inline函数

  • 优点
    直接展开,提高调用速度
  • 缺点
    每个地方都会展开,造成exe体积增大

inline声明的函数编译器可能会无视(如带递归的函数),而未被声明为inline的函数编译器可能优化为inline

C++32位和64位大小

32 64
char 1 1
short 2 2
int 4 4
float 4 4
double 4 4
指针 4 8
long 4 8
double 8 8

静态和动态链接库

https://blog.csdn.net/u010935076/article/details/51374388

linux windows
静态 .a .lib
动态 .so .dll
区别
  • 静态链接库使用时会被链接到目标代码中,编译出的程序会更大,而动态链接库是在运行时才会载入相应程序,编译出的程序更小
  • 静态链接库更新时,整个程序都要重新编译,动态链接库更新时只需重新编译动态链接库即可
  • 链接后,删除静态库不影响程序,删除动态库会报错(因为静态库会链接到目标代码中而动态库不会)
创建
  • windows下引入静态库使用
#pragma comment(lib, "test.lib")
  • windows下动态库
// 创建(会生成lib和dll)
extern "C" int __declspec(dllexport) func();
// 使用
#pragma comment(lib, "test.lib")
extern "C" int __declspec(dllimport) func();
  • linux下创建静态库使用ar命令
gcc -c hello.c  # 生成.o文件
ar cr libhello.a hello.o    # 生成.a文件gcc -o hello main.c -L. -lhello # 链接静态库
  • linux下创建动态库
gcc -c hello.c
gcc -shared -fPIC -o libhello.so hello.ogcc -o hello main.c -L. lhello
export LD_LIBRARY_PATH=$(pwd)   # 指定动态链接库搜索目录
  • 编译包含动态库的文件
g++ test.cpp -I./kms_api_1.3.1/1.3.1/include -L./kms_api_1.3.1/1.3.1/lib/lib/Tlinux1.2 -lkmshttpapi -L./kms_api_1.3.1/1.3.1/lib/lib/api_deps -lqos_client -o test每一个头文件都要包含,每一个动态库目录都要添加
export LD_LIBRARD_PATH也要包含上述目录:
export LD_LIBRARY_PATH=$(pwd)/kms_api_1.3.1/1.3.1/lib/lib/Tlinux1.2:$(pwd)/kms_api_1.3.1/1.3.1/lib/lib/api_deps
最好写到makefile中g++ demo_kmshttp.cpp -I../include -L../lib -lkmshttpapi -L../lib/kms_deps -lqos_client -lcurl -L../lib/kms_deps/ssl_dep -Wl,-rpath=../lib/kms_deps/ssl_dep -lssl -o demo_kmshttp
  • -shared表示指定生成动态链接库,没有该选项时生成的是可执行文件,无法被别的程序链接
  • -fPIC指示编译器编译成位置无关的代码,从而保证能链接到不同的程序当中
    静态和动态链接库同名时,优先使用动态链接库

程序内存分布

如何避免和判断内存泄漏

C++内存管理包括栈、堆、代码段、数据段(bbs)等,我们说的内存泄漏只出现在

  • 栈上的内存大小有限,由系统自动管理,申请内存时,就是指针下移,而当超出生命周期时,指针上移,相当于自动回收内存,栈上不会内存泄漏,只会栈溢出
  • 栈通常大小为2M,堆的最大大小和内存有关,通常为3G


VS中栈的默认大小是1M,linux中的默认大小是8M
linux中可以通过ulimit -a命令查看配置

[root@w3cschool.cc ~]# ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
pending signals (-i) 1024
max locked memory (kbytes, -l) 32
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
max user processes (-u) 4096virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited

避免内存泄漏
  • 使用智能指针
  • new完之后delete,malloc后free,free之后要置指针为null,避免出现野指针
  • 使用RAII技术
  • 尽量使用栈而不是堆上的资源
判断内存泄漏工具

gperftools,Valgrind

RAII

Resources Acquisition Is Initialized
栈上的内存由系统自动管理,当对象超出生命周期时会自动释放,利用这一特性,可以在栈上分配一个对象,每个对象的构造函数在堆上动态分配内存,在析构函数中释放内存,这样,当对象离开生存周期时,对象会自动调用析构函数,拥有的资源就会被释放

RAII的设计思想在于,将由堆上动态分配的内存与在栈上的对象的生存周期相绑定,实现将堆的手动管理交由堆来自动处理

https://www.jianshu.com/p/b7ffe79498be

RAII用于多线程环境中

定义一个锁结构,在构造函数中,持有锁,在析构函数中释放锁,从而避免使用锁时,忘记手动释放锁而引起死锁的问题

CRITICAL_SECTION cs;
class MyLock {
public:MyLock() {EnterCriticalSection(&cs);}~MyLock() {ExitCriticalSection(&cs);}
private:MyLock(const MyLock&);MyLock& operator=(const MyLock&);};unsigned int __stdcall ThreadFunc()
{MyLock lock;DoSomething(lock);//... // 退出时调用lock析构函数自动释放临界区资源
}

智能指针

shared_ptr,weak_ptr和unique_ptr
shared_ptr每增加一个引用引用计数+1
weak_ptr是弱引用,不会增加引用计数,用于解决shared_ptr的循环引用造成的内存泄漏问题,
unique_ptr只能指向一个对象,不可复制,赋值,但可以通过std::move转移

  • 用了shared_ptr后,就不要再使用new
  • 为避免循环引用,应当在创建对象时使用shared_ptr,在类内持有其他对象时使用weak_ptr

四种类型转换

  • static_cast
    最常用,C++的隐式转换就是用这个实现的
  • dynamic_cast
    用于多态的转换,因此必须有virual函数才行,如派生类指针转基类指针,但基类转派生类安全,但是会返回nullptr
  • reinterpret_cast
    强制转换,将一个类型的指针转换为另一个类型的指针,最常用的是将一个函数指针转换成另一个函数指针
  • const_cast
    去除const或volatile

内存对齐

  • #pragma pack(n)
  • alignas

一般按4的倍数字节寻址

https://blog.csdn.net/u013724478/article/details/85010951
C++中可以通过alignas变量设置

C++11新特性

  • 智能指针
  • 类型推导 auto关键字
  • delete关键字
  • nullptr
  • 范围for循环
  • using别名
  • 初始化列表
  • 委托构造,使用其他构造函数构造自身
  • lambda表达式
  • std::forward, std::move

A a(int);   // 构造函数
A a2(a);    // 拷贝构造
A a3 = a2;  // 拷贝构造
A a4;
a4 = a2;    // 拷贝赋值
  • C++用初始化列表初始化成员变量时,只与成员变量在类内定义的先后顺序有关,因为初始化列表初始化与变量在内存的次序有关,而这个次序在对类编译期间就确定了

为什么推荐用初始化列表初始化成员变量

见《Effective C++》条款四

  • const、引用类型必须要在初始化列表中实现
  • 在拷贝函数内部初始化时,其实是赋值操作,会先调用默认构造函数,然后再进行赋值,因此会有一定的开销

优雅的拷贝赋值运算符实现

Widget& operator=(const Widget &rhs)
{Bitmap *pOrig = pb; // 保存指针原来指向的内存pb = rhs.pb;        // 修改指针指向的内存delete pOrig;       // 释放原来指向的内存return *this;
}

虚函数

https://www.cnblogs.com/malecrab/p/5572730.html
建议仅用于需要多态的类中,因为虚函数需要在内存中存放,首地址指向实际调用的函数指针,会占用一定内存

1)子类会继承基类的虚函数表;
2)子类替换已经重写的虚函数指针;
3)追加子类自己的虚函数指针
注意

  • 如果继承了多个类,那么就会生成多个虚函数表;
  • 每个虚函数在类中占用4个字节,即一个指针大小
虚析构函数

用于多态基类,保证派生类的部分能被全部释放掉
如果基类不是虚析构函数,那么释放派生类对象时只会释放掉基类的部分

纯虚析构函数

使其变为抽象基类,仅在多态使用

class WOV {
public:virtual ~WOV() = 0;
};
WOV::~WOV() {}
设计一个不能被拷贝的类
// 这是一个空白基类
class UnCopyable {
protected:UnCopyable() {}~UnCopyable() {}
private:UnCopyable(const UnCopyable &rhs) {}UnCopyable& operator=(const UnCopyable &rhs) {}
};

然后让使用的类继承之:

class Widget : public UnCopyable {//...
};
空白类
class EmptyClass {};    // 空白类,但实际上会至少占用一个char的空间,用于内存对齐

但是在被继承时会被优化,被称为EMO(Empty Base Optimization)

class Widget : private EmotyClass{  // 继承空白基类,空白基类不占用空间,因此sizeof(Widget) == sizeof(x)
int x;
//...
};
虚继承

为解决多重继承而出现:
D继承自B,C,而B,C都继承自A,那么在构造D的时候,A就会被构造两次,采用虚继承即可避免此问题

虚函数

STL

迭代器失效

序列式容器

如vector,deque,删除迭代器会导致后续迭代器失效,因此需返回迭代器:

auto iter = vec.begin();
while (iter != vec.end()) {// vec.erase(iter); 迭代器失效iter = vec.erase(iter);++iter;
}
关联式容器

如map, set, multiset, multimap,底层实现是红黑树,删除迭代器仅导致当前迭代器失效,因此直接累加:

auto iter = m.begin();
while (iter != m.end()) {m.erase(iter++);
}
链表

STL的内存管理

小于128k的内存,用二级分配器,即内存池
大于128k的内存,用一级分配器分配,即malloc

  • 采用内存池的方式时,当请求的空间较小,每次都直接从内存池中获取满足大小的内存,分配和释放都在内存池上,开销较小;
  • 采用malloc需要到内存中分配,需要系统调用会切换到内核态

二级分配器
STL的二级分配器采用内存池,维护了8k,16k,24k…128k大小的内存块,使用一个空闲链表存储,每个链表的头结点用数组维护,当分配的内存小于128k时,会找到第一个满足大小的内存,释放时,将内存归还给该链表即可

GDB调试

  • backtrace
  • break
  • continue
  • clear
  • watch, rwatch, awatch
  • delete
  • enable, disable
  • next
  • step
  • catch
  • attach, detach
gdb riskctl_query_svr core.risksss  # 调试core,使用bt打印dump时的堆栈
dir /data/home/laurencexu/code/riskctl_query_proj/src/riskctl_query/    # 将改路径加入到gdb的搜索中
gdb -pid=   # 根据进程号调试
break riskctl_query_svr.cpp: 54 # 在指定文件加入断点
info break  # 查看断点信息
continue    # 执行到下一断点

调试守护进程

  1. 调试子进程的命令 set follow-for-mode child
    在调试守护进程(Daemon进程)的初始化函数时,因为真正做事的是后面启动的子进程,所以直接调试必然是不行的;如果等启动后attach到进程上,那就只有在循环里设断点了,又会错过初始化的过程。不知道这个命令前,做法都是初始化函数里打日志调试,那样就比较繁琐了。这时我们就可以通过设置 follow-for-mode 选项来决定程序启动后只跟踪子进程。
    默认设置下,在调试多进程程序时GDB只会调试主进程。但是GDB(>V7.0)支持多进程的分别以及同时调试。只需要设置follow-fork-mode(默认值:parent)和detach-on-fork**(默认值:on)**即可。
    follow-fork-mode 和 detach-on-fork 说明
    parent on 只调试主进程(GDB默认)
    child on 只调试子进程
    parent off 同时调试两个进程,gdb跟主进程,子进程block在fork位置
    child off 同时调试两个进程,gdb跟子进程,主进程block在fork位置
    设置方法:set follow-fork-mode [parent|child]

编程

  • rand()
int index = rand() % (e - b + 1) + e; // 生成[b, e]之间的随机数
  • emplace_back
    相比push_back而言避免了构造,降低开销

https://blog.csdn.net/qq_33850438/article/details/80172275 getopt_long的使用

https://blog.csdn.net/u010935076/article/details/51374388 linux下a和so的区别

https://baike.baidu.com/item/%E5%AD%97%E8%8A%82%E9%A1%BA%E5%BA%8F/10059170#4 网络字节顺序 主机地址 ip地址

实习秋招C++知识点总结相关推荐

  1. 实习秋招linux和网络编程知识点总结

    实习/秋招时按自己需求总结的知识点,内容并不十分详细,建议选择性阅读. 部分图片已失效. git常用命令速查表 git回滚 https://www.jianshu.com/p/f7451177476a ...

  2. 小蔓的秋招计算机知识点急救方法

    攒人品嘿嘿! 秋招来了,想要复习计算机知识点刷题,但又发现知识不连在一起,感觉东一棒槌西一榔头刷题浪费时间...怎么办? 秋招计算机知识点快速复习,打通任督二脉~有缘人速看!!(自我感觉不错仅供参考) ...

  3. 海康威视2019年校园招聘内推码(2019届春招、2020届实习/秋招)

    官宣拥有内推码的同学,同等条件择优录取,在每一个环节都会更加具有优势 海康威视2019年校园招聘内推码(2019届春招.2020届实习/秋招): 5S3QAI (最好复制内推码,不要写错了,写错了可能 ...

  4. 我的2018春招实习+秋招总结【前端开发】

    双非本科,通信工程,算是转到IT行业这边的了.从大二暑期正式开始学习前端,想想已经一年的时间了.期间经历了很多,从迷惘到清晰,从艰难自学到找到实习,从备战秋招到找到工作.能经历的我都经历过了.来说说那 ...

  5. Java面经:小米暑期实习+秋招真题分享

    秋招结束,总结了一下从寒假回来开始的实习生招聘和秋招面经,过来回馈一下牛客网. 上学期寒假回来就开始投简历,找人内推的小米,过几天后约时间面试,部门未知. 一面 1小时7分钟 上来先自我介绍,然后开始 ...

  6. 2018互联网实习秋招回顾(BATM+MS+Intel+NE+DJI)

    先介绍本人在2018年的暑期实习和秋招拿到的offer: 实习:阿里(c++后台研发),微软(c++后台开发),网易游戏(基础架构研发),大疆(测试开发),地平线(嵌入式软件开发),微策略(c++后台 ...

  7. 双非渣本的实习秋招路

    大家好,我是阿豪,双非渣本菜鸡一枚,没颜值,没技术,没存款,没对象........ 步入正题: 生活篇: 刚开始,我是在亲戚家住,距离公司比较远,每天上下班都要坐一个多小时的地铁,早上六点多起床,洗漱 ...

  8. 【前端春招】前端春招实习+秋招心路历程

    想写这篇由来已久了,大抵是自己比较懒惰,所以拖了这么久,从2021的3月份决定走前端然后春招开始,一直在白嫖面经帖子并受益良多,面经帖子很多,但是关于感受感想和一些经历的思考帖子不太多,在春招面试的路 ...

  9. 校招(春招实习 + 秋招)总结感想

    感谢 感谢Cyc2018, 感谢JavaGuide, 感谢其他给予我帮助的博主 春招 春招投递的基本都是大公司,网申投递了大概50+家公司,四月份拿到了兴业数金的实习offer, 五月份拿到了学而思的 ...

最新文章

  1. 神操作!美国程序员把工作外包给中国程序员,上班摸鱼吸猫年入 20 万美元
  2. 重装WIN7之后使用Ubuntu LiveCD修复grub2双系统引导
  3. CodeIgniter开发实际案例-新闻网站【转】
  4. arraylist 初始化_ArrayList实现原理(JDK1.8)
  5. 跟我一起学.NetCore之Asp.NetCore中集成Autofac扩展
  6. python有趣函数_python中有趣的函数
  7. Symbian系统开发教程(二)
  8. 【OpenCV】OpenCV实战从入门到精通之 -- 显示创建Mat对象的七种方法
  9. 蚂蚁金服自研数据库打败Oracle拿下世界第一;三星手机全面退出中国;微软发布Windows 10X双屏系统 | 极客头条...
  10. 落实业务服务管理从基础设施管理做起
  11. MCSA 70-740 windows 安装和部署工具汇总学习
  12. 绝对纯净:龙行天下GHOST XP SP3软件自选安装纯净版 2010 V13.0 2010年6月
  13. 如何下载安装fireBug
  14. 三相桥式全控整流电路simulink仿真_交流变直流,二极管整流电路是如何工作的?...
  15. idea 一直在updating index的问题
  16. sift论文_ImageNet一作邓嘉最佳论文,ECCV2020奖项全公布
  17. .bat、python与C++程序进行批量处理的学习与实践
  18. Vue+高德地图API的使用(点击地图搜索周边信息)
  19. 乐视电商云的整体架构与技术实现
  20. 块、内联、内联块都有哪些及其特点

热门文章

  1. windows phone 8 分辨率
  2. 7_数据存储持久化技术
  3. 使用递归实现归并排序及归并排序的时间复杂度
  4. 微信小程序 ios 橡皮筋效果踩坑
  5. 图片/音频/视频/文字相关软件
  6. 如何设置与查看Linux系统中的环境变量?
  7. 深度学习常见网络结构
  8. [SDOI2010] 魔法猪学院
  9. 【C语言】自定义类型——计算结构体内存对齐
  10. onTouchEvent / MotionEvent(轨迹球事件、触摸屏事件、键盘事件)