Mudo C++网络库第十一章学习笔记
反思C++面向对象与虚函数
- C++语言学习可以看《C++ Primer》这本书;
- 在C++中进行面向对象编程会遇到其他语言中不存在的问题, 其本质原因是C++ class是值语义, 而非对象语义;
朴实的C++设计
- 实用当头, 朴实为贵, 好用才是王道;
- C++ 是一门(最)复杂的编程语言, 语言虽复杂, 不代表一定要用复杂的方式来使用它;
- 不一定非得有基类和派生类的设计才是好设计;
- 一个类代表一个概念;
- 让代码保持清晰, 给我们带来了显而易见的好处;
- 不要因为某个技术流行而去用它, 除非它确实能降低程序的复杂度;
- 在C++这样需要自己管理内存和对象生命期的语言里, 大规模使用面向对象、继承、多态多是自讨苦吃;
C++编译器ABI的主要内容主要包括几个方面:
- 函数传递的方式, 比如x86-64用寄存器来传函数的前4个整数参数;
- 虚函数的回调方式, 通常是vptr/vtbl机制, 然后用vtbl[offset]来调用;
- struct和class的内存布局, 通过偏移量来访问数据成员;
- name mangling;
- RTTI 和异常处理的实现;
- 避免使用虚函数作为库的接口;
- 因为这样会给保持二进制兼容性带来很大的麻烦;
- JAVA的库都是.jar文件;
虚函数作为库的接口的两大用途
- 调用;
- 回调, 也就是事件通知, 比如网络库的连接建立, 数据到达, 连接断开等;
- 混合使用;
iostream的用途与局限
- C++ iostream的主要作用是让初学者有一个方便的命令行输入输出试验环境, 在真实的项目中很少用到iostream;
- 不用花大量的精力在iostream的格式化与manipulator(格式操作符)上;
- glibc定义的getline函数来读取不定长的行;
- 返回的是malloc()分配的内存, 要求调用端自己free()掉;
- iostream不是线程安全的;
- 用到了多重继承和虚拟继承;
- Google Protobuf是一种高效的网络传输格式, 它用一种协议描述语言来定义消息格式, 并且自动生成序列花代码;
- C++的强大之处在于抽象不以性能损失为代价;
- 数据抽象(data abstraction)是与面向面向对象(object-oriented)并列的一种编程范式(programming pragadigm);
数据抽象所需的语言设施
- 支持数据聚合(data aggregation);
- 全局函数与重载;
- 成员函数与private数据;
- 拷贝控制(copy control);
- C++ class是值语义, copy control是实现深拷贝的必要手段, 而且ADT用到的资源只涉及动态分配的内存, 所以深拷贝是可行的;
- 操作符重载;
- 效率无损, 抽象不代表低效;
- 在C++中, 提高抽象的层次并不会降低效率;
- 模板与泛型;
- 数据抽象是C++的重要抽象手段, 适合封装数据, 它的语义简单, 容易使用;
- 大多数class都是对象语义;
C++经验谈
- 练从难处练, 用从易处用;
- 软件开发一定要时刻注意减少不必要的复杂度;
- 作为应用程序的开发者, 对技术的运用要明智, 不要为了了解难度系数为10的问题而去强攻难度系数为100的问题, 这就本末倒置了;
- 用异或来交换变量是错误的;
- 未定义的行为, 在C/C++语言的一条语句中, 一个变量的值只允许改变一次(像x = x++这种代码都是未定义行为, 因为x有两次写入);
- 现在的编译器会把std::reverse()这种简单函数自动内联展开, 生成出来的优化汇编代码和其他代码一样快;
- 不要猜(guess), 要测(benchmark);
- 不要重载全局::operator new();
- 按现代C++的手法(RAII)来管理内存, 很难遇到什么内存方面的错误;
- 内存管理的基本要求:
- 内存管理的基本要求是不重不漏 -- 既不重复delete, 也不漏掉delete;
- new/delete配对, 不仅是个数相等, 还隐含了new和delete的调用本身要匹配, 不要东家借的东西西家还;
- 用系统默认的malloc()分配的内存要交给系统默认的free()去释放;
- 用系统默认的new表达式创建的对象要交给系统默认的delete表达式去析构并释放;
- 用系统默认的new[]表达式创建的对象要交给系统默认的delete[]表达式去析构并释放;
- 用系统默认的::operator new()分配的内存要交给系统默认的::operator delete()去释放;
- 用placement new创建的对象要用placement delete(为了表述方便, 姑且这么说吧)去析构(其实就是直接调用析构函数);
- 从某个内存池A分配的内存要还给这个内存池;
- 如果定制new/delete, 那么要按规矩来;
- 检查代码中的内存错误;
- 优化性能;
- 获得内存使用的统计数据;
- 脚本语言解释器代码:
- Python的代码很好读;
- C语言的static关键字的两种用法:
- 用于函数内部修饰变量, 即函数内的静态变量; 使用静态变量的函数一般是不可重入的, 也不是线程安全的;
- 用在文件级别(函数体之外), 修饰变量或函数, 表示该变量或函数只能在本文件可见, 其他文件看不到, 也访问不到该变量或函数(interal linkage);
- C++语言的static关键子的四种用法:
- static关键字又有了两种新用法: 用于修饰class的数据成员, 即所谓的静态成员, 这种数据成员的生存期大于class的对象(实体/instance);
- 静态成员是每个class有一份, 普通数据成员是每个instance(实例)有一份, class variable(类变量)和instance variable(实例变量);
- 用于修饰class的成员函数, 即所谓的静态成员函数, 静态成员函数只能访问class variable和其他静态程序函数, 不能访问instance variable或instance method;
- 协议设计是网络编程的核心:
- 消息格式: XML, JSON, Protobuf, 难的是消息内容;
- 网络编程的三个层次:
- 读过教程和文档, 做过练习 -- 读过《UNIX网络编程》《TCP/IP详解》并理解TCP/IP协议, 读过本系统的manpage;
- 熟悉本系统TCP/IP协议栈的脾气;
- 有可能出现TCP自连接(self-connection), 程序应该有所准备;
- Linux内核会有bug, 比如某种TCP拥塞控制算法曾经出现TCP window clamping(窗口错位)bug, 导致吞吐量暴跌, 可以选用其他拥塞控制算法来绕开(work around)这个问题;
- 自己写过一个简单的TCP/IP stack;
- TCP网络编程有三个例子最值得学习研究: 分别是echo, chat, proxy都是长连接协议;
- proxy的作用: 连接的管理更加复杂, 既要被动接受连接, 也要主动发起连接, 既要主动关闭连接, 也要被动关闭连接, 还要考虑两边速度不匹配;
- 三本必看的书:
- 谈到Unix编程和编程编程, W.Richard Stevens是个绕不开的人物;
- [APUE]、两卷《UNIX网络编程》、三卷《TCP/IP详解》;
- [UNPv2]其实跟网络编程关系不大, 是[APUE]在多线程和进程间通信(IPC)方面的补充;
- 《TCP/IP详解》三卷, 用处不同, 应该区别对待;
- 第一本《TCP/IP Illustrated, Vol. 1: The Protocols》(TCP/IP详解);
- 从使用者(程序员)的角度, 以tcpdump为工具, 对TCP协议抽丝剥茧, 娓娓道来;
- TCP作为一个可靠的传输层协议, 其核心有三点:
- Positive acknowledgement with retransmission(对重传的积极响应) -- 可靠性;
- Flow control using sliding window(包括Nagle算法等) -- 提高吞吐量;
- Congestion(拥塞) control(包括slow start、congestion avoidance、fast retransmit) -- 防止过载造成丢包;
- TCP像是一个自适应的节流阀, 根据管道的拥堵情况自动调整阀门的流量;
- 第二本《Unix Network Programming, Vol.1:Networking API》统称UNP;
- UNP是Sockets API的权威指南;
- 网络编程远不是使用那十几个Sockets API那么简单, 一定要熟悉TCP/IP协议及其外在表现(比如打开和关闭Nagle算法对收发包延时的影响);
- UNP中问版《UNIX网络编程》翻译得相当好, 译者杨继张先生是真懂网络编程的;
- UNP很详细, 面面俱到, UDP、TCP、IPv4、IPv6都讲到了;
- 讲得太详细, 重点不够突出;
- 在具备基础之后, 学习任何新东西, 都要抓住主线, 突出重点, 对于关键理论的学习, 要集中精力, 速战速决;
- 作者是先看的TCPv1, 花了大约两个月的时间, 然后再读UNP和APUE;
- 第三本《Effective TCP/IP Programming》;
- 这本书属于专家经验总结类的书籍;
- 还值得一看的书:
- 《TCP/IP Illustrated, Vol.2: The Implementation》, 称为TCPv2;
- 工作中大可以把IP视为host-to-host的协议;
- 《Pattern-Oriented Software Architecture Volume 2: Patterns for Concurrent and Networked Objects》, 简称POSA2;
- 这本书总结了开发并发网络服务程序的模式, 是对UNP很好的补充;
- POSA2强调模块化, 网络通信交给library/framework去做, 程序员写代码只关注业务逻辑(这是非常重要的思想);
- 这本书对深入理解常用的event-driven网络库(libevent, Java Netty, Java Mina, Perl POE, Python Twisted)也很有帮助;
- POSA2的代码是示意性的, 思想很好, 细节不佳;C++代码没有充分考虑资源的自动化管理(RAII);
- 谈到Unix编程和编程编程, W.Richard Stevens是个绕不开的人物;
- 很多企业内部使用C++来构建自己的分布式系统基础架构, 并且有替换Java开源实现的趋势;
- 学习C++只需要读一本大部头《The C++ Programming Language》或《C++ Primer》;
- 《C++ Primer》的主要内容是精解C++语法(syntax)与语意(semantics)并介绍C++标准库的大部分内容(含STL);
- C++的开源库: Google的Protobuf, leveldb, PCRE的C++封装, 还有就是作者的muduo库;
- 如有时间可以读读Chromium中基础库源码, 在读Google开源的C++代码时要连注释一起细读;
- 不建议一开始就读STL或Boost的源码, 因为编写通用的C++模板库和编写C++应用程序的知识体系相差很大;
- 《Effective C++中文版》,《泛型编程与STL》, 《C++编程规范》;
- 避免写出依赖于函数实参求值顺序的代码, C++操作读的优先级、结合性与表达式的求值顺序是无关的;
- Google的C++编程规范和LLVM编程规范;
Mudo C++网络库第十一章学习笔记的更多相关文章
- Mudo C++网络库第六章学习笔记
muduo网络库简介 高级语言(Java, Python等)的Sockects库并没有对Sockects API提供更高层的封装, 直接用它编写程序很容易掉到陷阱中: 网络库的价值还在于能方便地处理并 ...
- Mudo C++网络库第四章学习笔记
C++多线程系统编程精要 学习多线程编程面临的最大思维方式的转变有两点: 当前线程可能被切换出去, 或者说被抢占(preempt)了; 多线程程序中事件的发生顺序不再有全局统一的先后关系; 当线程被切 ...
- Mudo C++网络库第三章学习笔记
多线程服务器的适用场合与常用编程模型 进程间通信与线程同步; 以最简单规范的方式开发功能正确.线程安全的多线程程序; 多线程服务器是指运行在linux操作系统上的独占式网络应用程序; 不考虑分布式存储 ...
- Mudo C++网络库第七章学习笔记
muduo编程示例 muduo库是设计来开发内网的网络程序, 它没有做任何安全方面的加强措施, 如果在公网上可能会受到攻击; muduo库把主动关闭连接这件事分成两步来做: 如果主动关闭连接, 会先关 ...
- Mudo C++网络库第五章学习笔记
高效的多线程日志 日志(logging)有两个意思: 诊断日志(diagnostic log), 常用日志库提供日志功能; 交易日志(transaction log), 用于记录状态变更, 通过回放日 ...
- 网络库Alamofire使用方法学习笔记
Github地址 由于Alamofire是swift网络库,所以,以下的所有介绍均基于swift项目 导入Alamofire 以下为使用cocoapods导入,其余的方式请参考官网 source 'h ...
- 《Linux内核设计与实现》 第一二章学习笔记
<Linux内核设计与实现> 第一二章学习笔记 第一章 Linux内核简介 1.1 Unix的历史 Unix的特点 Unix很简洁,所提供的系统调用都有很明确的设计目的. Unix中一切皆 ...
- 《Linux内核设计与实现》第一、二章学习笔记
<Linux内核设计与实现>第一.二章学习笔记 姓名:王玮怡 学号:20135116 第一章 Linux内核简介 一.关于Unix ——一个支持抢占式多任务.多线程.虚拟内存.换页.动态 ...
- 《Linux内核设计与实现》课本第五章学习笔记——20135203齐岳
<Linux内核设计与实现>课本第五章学习笔记 By20135203齐岳 与内核通信 用户空间进程和硬件设备之间通过系统调用来交互,其主要作用有三个. 为用户空间提供了硬件的抽象接口. 保 ...
随机推荐
- Mac下显示网页全屏快捷键
control+command+F mac下谷歌浏览器全屏时隐藏头部:(隐藏标签页和地址栏) command+shift+B
- windows cmd命令 批处理bat 导增量jar包【原】
下载地址 https://pan.baidu.com/s/1cIyCbG 导jar包 @echo off setlocal enabledelayedexpansion echo ---------- ...
- PHPMYWIND4.6.6前台Refer头注入+后台另类getshell分析
下载链接 https://share.weiyun.com/b060b59eaa564d729a9347a580b7e4f2 Refer头注入 全局过滤函数如下 function _RunMagicQ ...
- adduser Ubuntu添加sudo用户
第一种方法: 添加sudo用户 当你安装Ubuntu的时候,它会自动添加第一个用户到sudo组,允许这个用户通过键入其自身帐户密码来获得超级用户(root)身份.然而,系统不会再自动添加其他的用户到s ...
- jquery 控制 video 视频播放和暂停
$('video').trigger('play'); $('video').trigger('pause'); 参考:https://blog.csdn.net/arvin0/article/det ...
- ubuntu终端命令启动matlab方法
让所有用户都有权限使用matlab,在终端输入 sudo gedit /etc/profile 在后行写 export MATLABPATH=/home/ubuntu/MATLAB/R2016b:$M ...
- dbms_redefinition在线重定义表结构
dbms_redefinition在线重定义表结构 (2013-08-29 22:52:58) 转载▼ 标签: dbms_redefinition 非分区表转换成分区表 王显伟 在线重定义表结构 在线 ...
- Docker 容器启动 查看容器状态 - 四
1.容器两种方式进行启动 一种是基于创建一个容器并启动 docker create docker start 另一种 使用 run 创建自动启动:是状态下的停止 启动 docker start ngi ...
- [C++]Linux之头文件sys/types.h[/usr/include/sys]
1.查找<sys/types.h>文件 一般地,Linux的C头文件<sys/types.h>路径在如题的途径:/usr/include/sys下,然而博主[Linux For ...
- 第26月第20天 springboot
--------------------- 1.pom.xml中添加支持web的模块: <dependency> <groupId>org.springframework.bo ...