c++

记录

Shared Library

* 编译,链接,静态库与动态库 * 预备知识 * 编译: * Relocation * 静态链接 * 动态链接 * 细节问题 * 动态链接器如何确定可执行文件的所有依赖? * 文件定位的规则 * 动态relocation细节 * dlopen * fPIC * 控制DSO的dynsym符号导出 * Versioning (Version script) * Interpose * Good Practice 正确而高效的使用动态库是一个很复杂的话题,这需要开发者编译和链接有相当深入的理解. 本文主要关注"正确使用",这已经足够复杂. 这里主要是描述linux/gnu体系下编译器/链接器的行为(可能不适合其他系统,甚至不适合老版本的linux工具链), 这些行为的设计一般都有历史因素及兼容性的考量,所以某些部分可能看起来不够优美. 编译,链接,静态库与动态库 预备知识 编译: * 将单个编译

By Edimetia3D

记录

A note for cmake

A Note for CMake CMake可以说是目前C++项目的标准构建系统, 尽管它有很多不足, 但是它已经成功的替换掉了autoconf这一代的构建工具. 除非有足够的理由, 在选择构建系统时, CMake总是应当第一优先考虑. 我熟悉的构建系统只有CMake和Bazel, 事实上, 如果能满足若干客观条件的话, 我更愿意使用Bazel, 不过这篇主要记录的是CMake, 所以还是以CMake为主. 在我看来, CMake主要的优缺点如下: Pros: 1. Imperative: 可以把CMake当做一个脚本语言来阅读, 这更符合大家的编程习惯. 2. Widely-used: 你只要大致会使用CMake, 那么世界上的大部分项目都可以被你使用了. 3. Easy-at-beginning: 上手成本很低, 简单的binary和library都很容易被描述出来, 对新手友好. Cons: 1. Too many traps: 你必须要非常熟悉CMake, 才能写出稳定可靠的CMake脚本, 否则, 处处都有坑你的陷阱. reddit上曾有一个评

By Edimetia3D

未分类

A Strory of Mixin

Mixin Mixin是一种设计思想, 主要内容是: Mix some MixinClass into a CoreClass, so the CoreClass can get some new feature, or get enhanced. 与其他设计模式相比, Mixin的主要特点是它没有固定的编程pattern, 只是一种指导思想, 所以可能会有各种各样的具体设计自称为"Mixin", 因此, 当你看到一个"Mixin"设计时, 常常会想"我用XX不也可以实现这样的效果吗?", 这是非常正常的. 一般而言, 当设计实现了Mixin时, 常常会有以下特点: 1. 使用多继承或链式继承, 因为我们常常需要把多个MixinClass混合到CoreClass中,使用多继承或链式继承是非常直观的方法. 2. 尽管使用了继承, 但是一般不进行"覆写&

By Edimetia3D

记录

设计模式

For C/C++ user 很多设计模式相关的资料都是用Java来描述的,有必要简单补充一下Java和C++在OOP技术层面上的区别 * Java不支持任何形式的运算符重载 * Java明确区分接口和类,类只能从一个类派生,但是一个类可以实现多个接口 * 在Java中,所有方法默认是虚(virtual)的 * 对CPP而言,Java风格的接口可以视为一个只有pure virtual成员函数的基类,称为Interface * implement,is-a(inherit),has-a * implement: 特指继承Interface,并通过override实现其中函数的行为. * is-a: 特指继承普通类后,普通类和基类的关系. * has-a: 特指持有某个对象. 杂谈 * 设计模式可以说就是各种各样的"OOP最佳实践方法". 一个设计模式对应了一种组织代码的风格,对应了一种解决问题的策略. * 设计模式可以说是程序员的"行话",使用"行话"有利于交流,但是并不一定有利于问题的解决,简单优雅的解决问题总是

By Edimetia3D

C++系列

SomeCpp

零碎知识点 * fflush仅仅是为了输出而设计的, 标准中并没有说明它对输入缓冲的效果. * 一元运算符和=是右结合的,这和<<是完全不同的,a=b=c意味着a=(b=c),b=c将先执行,而a<<b<<c则是(a<<b)<<c,a<<b将先执行. * C++11后引入了thread_local型的生命周期,这种对象和线程的生命周期是一致的 * C++11中很多类型都支持列表初始化,a = {value1,value2...} * 列表初始化会额外检测是否可能存在信息丢失,如果可能存在丢失,则无法通过编译期检查. * 对于自定义类,支持列表初始化意味着存在这样的ClassName(initializer_list&

By Edimetia3D

C++系列

Some Multi Thread

C++标准库提供的 mutex 在大部分场合都足以保证线程安全, 但是当问题变得更加极端时,就可能需要使用lockfree风格的并行编程了. 而为了正确实现lockfree, 你将打开一扇新的大门, 接下来的名词都是在学习过程中必须正确理解的: memory model, reordering, weak(relax), strong(strict), fence, barrier, release, acquire, seq_cst, consume, mutex, futex, lockfree(lockless), synchronize-with, happens-before, ABA, DCLP, 背景 在单核时代,CPU设计中引入了很多特性,其中很重要的一点就是乱序执行,乱序执行的基本原则是:乱序执行的最终效果应当和顺序执行一致,这个原则在单线程下是比较容易保证的.例如,对于下面的代码,先写入a还是先写入b都不影响后序的指令执行的正确性,所以编译器及硬件都可以自行选择先执行哪一个. a = 8; b = 9; 当进入并行环境之后,乱序执行的基本原

By Edimetia3D

布道

Python for C++ Programner

这里谈一下个人的学习建议. 首先可以阅读官方的入门教程, 看完这一部分, 对于一个熟练的C++程序员, 应该可以凑合写出可堪一用的代码了. 对于大部分不以Python为主要工作语言的开发者,到此基本就足够了. 如果有时间,我建议直接阅读Python in a Nutshell第七章之前的内容(不含第七章),并不用完全看懂,大部分细节也不用去记忆,只需要看完即可,至此,你就能基本了解Python的运行机制, 写出质量稳定可控(不会存在低级错误)的代码了. 上面两步完成后, 对一个熟悉C++的程序员而言, 基本任何Level的Python资料都可以看了. 你可以继续看Python in a nutshell中感兴趣的部分,也可以选择Fluent Python. 在有相当多的开发经验之后,可以阅读Python Cookbook. 如果仍然想进一步深入, 那么你应该直接学习CPython解释器的实现,Python Developer’s Guide可以作为一个入口. 最后,本文仅仅简单扼要的说明了Python和C++不同的一些特性, 可以作为补充阅读. 书评

By Edimetia3D

C++系列

C++ OOP编程综述

嵌套类和局部类 * 定义在类X内的类Y称为嵌套类,它就是一个普通类,只不过使用的作用域被限制了. * 定义在函数内的类Y称为局部类,这种类限制很多,主要用于在语言层面支持Lambda,实践中基本不用. struct(class)的内存布局 * C++的struct和class实例大小不会为0,即便它内部没有任何数据变量.主要是因为编译器总是需要为实例分配内存,使得对象能获得有效的地址,且不同对象的地址总应该是不同的. * 类型布局相关的名词有很多,如POD,Aggragate,naive等,具体我也不是很清楚,总之很麻烦. * 如果需要把sturct或class对象通过C风格直接从内存层面管理(如memcpy),那么要求它的内存布局是平凡的. * 只要类型涉及到virtual, 那类型实例的首地址存储的一定是vptr, 涉及virtual只需满足任意一个条件: * 直接或间接使用虚继承 * 直接或间接使用虚函数 一般规则 C++对象的内存布局对于理解多继承/虚继承非常重要, 基本要关注的有三点 1

By Edimetia3D

C++系列

[Cpp基础][11]"异常"

异常 * C++内所说的异常是指:可以预见的非正常状况,例如输入的指针为空;而非不可预见的问题,例如突然停电,或者突然被用户把进程kill掉,并不是C++需要处理的"异常" * 异常特性会导致程序的执行流程不可控,且往往对OS及runtime有一定的要求(可移植性差),所以没有特殊需求时,不应当使用这个特性. * throw-try-catch是异常系统的典型三个环节. * throw出的可以是任意对象,只要catch处声明的对象可以用throw的对象初始化即可.习惯上我们会专门设计一个类,因为自定义类可以承载更多的信息 * 异常catch中的形参可以使用引用,以使用多态机制 * 异常抛出后寻找catch的过程称为栈展开,被展开的函数栈内所有局部对象都将被销毁,因此抛出的异常对象必须不依赖局部对象. * 标准库内提供了以exception为基类的若干异常,我们可以使用这个类,也可以自定义类,该类的const char * what()成员用于给用户提供信息. * catch时,优先使用引用, 从而保证能派生类实例能绑定到基类参数上

By Edimetia3D

C++系列

[Cpp基础][10]重载运算符

重载运算符 规定 * 赋值,取下标,调用,箭头,类型转换,这些运算符只能作为成员函数. * 用户重载的&&与||不会进行短路求值. 习惯 * 重载主要分为全局重载和类内重载,一般而言,二元运算都应该在全局重载(顺序问题). * 改变对象状态的运算符一般应当设为成员函数,拥有对称性的运算符一般应在类外重载. * 从技术层面说,重载运算符的参数可以是指针类型的,但是这一般与我们使用语言的习惯不符,所以形参类型最好只是T或T&,而不要是指针. * 定义有关联的重载运算符时一定要考虑兼容性,例如a<b为假,a>b也为假,那么a==b就应该返回真. * 重载中应当尽可能的保持语义与内置风格一致. * 例如,如果重载了++运算符,那么应当保证++x和x+=1及x=x+1有同样的效果. * 尽量不要重载全局的operator new,仅在类内重载它. * 类内重载的new和delete都是static的,因此,无法使用this相关的量

By Edimetia3D