More effective C++摘要
3 基础议题部分:
3.1 M1:指针与引用的区别
首先,要认识到在任何情况下都不能使用指向空值的引用,引用必须被初始化。一个引用必须总是指向某些对象。
(不存在指向空值的引用意味着使用引用的代码效率比使用指针的要高)
其次,指针可以被重新赋值以指向另一个不同的对象。
什么情况下应该使用指针? 1存在不指向任何对象的可能。 2能够在不同时刻指向不同对象
什么情况下应该使用引用? 1总是指向一个对象并且不会改变指向 2重载某个操作符时
 
3.2 M2 尽量使用C++风格的类型转换
为什么不使用C风格?1,过于粗鲁,允许在任何类型之间进行转换; 2,C风格的类型转换在程序语句中难以识别
 C++新引进的风格
1 static_cast 在功能上基本上与C风格的类型转换一样强大,也有功能上的限制。但是不能从表达式中去除const属性
2 const_cast 用于类型转换掉表达式的const或者volatileness属性。最普通的用途是转换掉对象的const属性
3 dynamic_cast 用于安全的沿着类的继承关系向下进行类型转换。即把指向基类的指针或引用转换成指向其他派生类或者其兄弟类的指针或引用。失败的转换将返回空指针或者抛出异常
4 reinterpret_cast 转换结果都是执行期定义,最普通的用途就是在函数指针类型之间进行转换,但这种转换是不可移植的
 
3.3 M3 不要对数组使用多态
通过一个基类指针来删除一个含有派生类对象的数组,结果将是不确定的,指针和多态不能混在一起用,数组和多态也不能混在一起用。
BST BSTArray[10]; 数组中,参数array被声明为BST类型,所以array数组中每一个元素都是BST类型,因此每个元素与数组起始地址的间隔是i*sizeof(BST)。但是如果把BalancedBST对象的数组变量传递给该数组,派生类的长度通常都比基类要长,数组定位指针算法将是错误的。

3.4 M4 避免无用的缺省构造函数
提供无意义的缺省构造函数也会影响类的工作效率。使用这种(没有缺省构造函数的)类的确有一些限制,但是当你使用它时,它也给你提供了一种保证:你能相信这个类被正确地建立和高效地实现。
 
4 运算符部分:
4.1 M5 谨慎定义类型转换函数
两种函数允许编译器进行隐式转换:单参数构造函数和隐式类型转换运算符。
1,什么是单参数构造函数?
单参数构造函数可以是只定义了一个参数,也可以是虽然定义了多个参数但第一个参数以后的所有参数都有缺省值。
2, 隐式类型转换运算符只是一个样子奇怪的成员函数:operator,其后跟一个类型符号。你不用定义函数的返回类型,因为返回类型就是这个函数的名字。
3,隐式类型可以转换为显式转换函数(asDouble),虽然不方便,可以避免错误。即通过不声明运算符operator的方法。
4,对于单参数构造函数,可以利用最新编译器的特性,explicit关键字。构造函数如果用explicit声明,编译器会拒绝为了隐式类型转换而调用构造函数
  
4.2M6自增(++)自减(--)操作符前缀与后缀形式的区别
1C++规定后缀形式有一个int类型参数,当函数被调用时,编译器传递一个0作为int参数的值
  UPInt& operator++();                   // ++ 前缀
  const UPInt operator++(int);              // ++ 后缀 
所以i++++错误,不允许,得不到正确的结果。所以,前缀的形式效率高,多使用。
2这些操作符前缀与后缀返回值类型不同。前缀形式返回一个引用,后缀形式返回一个const类型。因为:前缀形式有时叫做“增加然后取回”,操作的是当前的数据,故&;后缀形式叫做“取回然后增加”,操作的不是当前数据,故const。
 
4.3 M7不要重载”&&”和”||”和 “,”
1, &&和||是短路求值的:如果重载了这些,那么你以“函数调用”法替代了短路求值法,与C++规范不一致了
if (expression1 && expression2) ...等于
if (expression1.operator&&(expression2)) ...或者
if (operator&&(expression1, expression2)) ...。  不是短路操作。
2,逗号操作符,一个包含逗号的表达式首先计算逗号左边的表达式,然后计算逗号右边的表达式;整个表达式的结果是逗号右边表达式的值。

4.4 M8理解各种不同含义的new和delete
共有三种不同形式的new
1 new 操作符 new operator    string *ps = new string(“Memory Management”)
 第一 分配足够的内存以便容纳所需类型的对象
 第二 调用构造函数初始化内存中的对象
 
2 new操作 operator new 是new操作符为分配内存所调用函数的名字 
 所以operator函数只是用来分配内存,而且对构造函数一无所知。
void *operator new (size_t size) ,void *ramMemory = operator new(sizeof(string));
 
3 placement new
 特殊的operator new,,在已经被分配但是尚未处理的内存构造一个对象
 Placement new返回指向该内存的指针,因为operator new 的目的是为对象分配内存然后返回指向该内存的指针。
 Void *operatore new(size_t size,void *location){ Return location;}
new(buffer) Widget(widgetSize)
 
4 如何选取使用这三种不同类型的new
1) 如果想在堆上建立一个对象,选用new操作符。既分配内存又为对象调用构造函数
2) 如果仅仅分配内存,就调用operator new函数,不会调用构造函数
3) 如果在已经获得指针的内存里建立一个对象,应该用placement new
Delete:operator delete与delete operator,       Operator new 与new operator
Delete ps:调用析构函数并释放对象占有的内存
Operator delete(buffer)仅仅释放资源到内存
 
5异常部分:
如果一个函数通过设置一个状态变量或返回错误代码来表示一个异常状态,没有办法保证函数调用者将一定检测变量或测试错误代码。结果程序会从它遇到的异常状态继续运行,异常没有被捕获,程序立即会终止执行。

5.1 M9使用析构函数防止资源泄漏
使用auto_ptr,在构造函数里面,让一个指针指向一个堆对象或者需要释放的系统资源,并在析构函数里删除这个对象。
隐藏在auto_ptr后的思想是:用一个对象存储需要被自动释放的资源,然后依靠对象的析构函数来释放资源。
template <class T>
class auto_prt{
public:  auto_ptr(T *p=0): ptr(p) {}
 ~auto_ptr(){delete ptr;}
private: T *ptr;};
 
5.2M10在构造函数中防止资源泄漏
C++只能删除被完全构造的对象,只有对象的构造函数完全运行完毕,这个对象才能被完全的构造;所以构造函数中出现泄漏的话,析构函数不能被调用。在构造函数中,处理各种抛出异常的可能,采用auto_ptr,可以化繁为简
Auto_ptr特点:指向动态分配的对象的指针,当指针消失的时候,对象也应该被删除

5.3M11禁止异常信息传递到析构函数
1,如果在一个异常被激活的同时,析构函数也抛出异常,并导致程序控制权转移到析构函数外,C++将调用terminate函数。这个函数的作用正如其名字所表示的:它终止你程序的运行,而且是立即终止,甚至连局部对象都没有被释放。
所以,这样做:能够在异常转递的堆栈辗转开解(stack-unwinding)过程中,防止terminate被调用。
2,如果一个异常被析构函数抛出而没有在函数内部捕获住,那么析构函数就不会完全运行(它会停在抛出异常的那个地方上)。如果析构函数不完全运行,它就无法确保析构函数总能完成我们希望它做的事情
 
5.4 M12 理解“抛出一个异常”与“传递一个参数”或“调用一个虚函数”间的差异
相同点:可以传值,传递引用或者传递指针;造成程序流程改变并返回一些状态;
不同点:1函数调用,程序的控制权最终还会返回到函数的调用处;抛出异常,控制权永远不会回到抛出异常的地方。
2抛出异常的速度比参数传递慢。不论通过传值或传递引用(指针不是),都将进行强制异常对象copy操作,因为异常导致了生命周期结束,C++规范要求被做为异常抛出的对象必须被复制。当异常对象被copy时,拷贝操作是对象的静态类型所对应的拷贝构造函数,而不是对象的动态类型。
所以:异常对象在传递时基本上被进行拷贝;当通过传值方式捕获时,异常对象被拷贝了两次。对象做为参数传递给函数时不一定需要被拷贝。
3异常抛出比参数传递转换类型要少,支持的类型转化少,仅支持两种类型:1)继承类与基类的转换 2)允许从一个类型化指针转变成无类型指针,所以带有const void* 指针的catch子句能捕获任何类型的指针类型异常.
4 catch子句进行异常类型匹配的顺序即为他们在代码中出现的顺序,第一个类型匹配成功的catch将用来被执行。当一个对象调用一个虚拟函数时,被选择的函数位于与对象类型匹配最佳的类里,即使该类不是在源代码的最前头。
5(zhs)如果一个函数通过设置一个状态变量或返回错误代码来表示一个异常状态,没有办法保证函数调用者将一定检测变量或测试错误代码。结果程序会从它遇到的异常状态继续运行,异常没有被捕获,程序立即会终止执行。

5.5 Item13通过引用(reference)捕获异常
通过指针捕获异常虽说不能引起对象copy,效率高,但是不符合C++语言本身的规范。四个标准的异常――bad_alloc(当operator new不能分配足够的内存时,被抛出),bad_cast(当dynamic_cast针对一个引用操作失败时,被抛出),bad_typeid(当dynamic_cast对空指针进行操作时,被抛出)和bad_exception(用于unexpected异常)――都不是指向对象的指针,所以你必须通过值或引用来捕获它们。
因为通过使用引用捕获异常,可以避开(类似于指针那样)异常对象是否已经被删除而烦恼,能够避开(类似于传值那样)slicing异常对象,减少异常对象需要被拷贝的数目。
 
5.6Item 14 谨慎使用异常规格(exception specification)
异常规格明确地描述一个函数可以抛出什么样的异常 void f2() throw(int),但是实际上,不抛出int异常也是允许的。

5.7Item15了解异常处理的开销
与一个正常的函数返回相比,通过抛出异常从函数里返回可能会慢三个数量级

6效率
6.1 Item M16 牢记80-20准则
80─20准则说的是大约20%的代码使用了80%的程序资源,即软件整体的性能取决于代码组成中的一小部分。使用profiler来确定程序中的那20%,关注那些局部效率能够被极大提高的地方。

6.2 Item M17 考虑使用LAZY EVALUATION(懒惰计算法)
采用此种方法的类将推迟计算工作直到系统需要这些计算的结果。
1,引用计数:除非确实需要,不去为任何东西制作拷贝。比如Copy-on-write。
2,区分对待读取与写入:operator[]因为读取很容易,然而写入这个string则需要在写入前做一个copy,可以用代理类来实现。  3,懒惰存取:Lazy Fetch 每次不从磁盘上读取所有数据。  4,懒惰表达式计算

6.3 Item M18 分期摊还期望的计算
过度热情计算法(over-eager evaluation),如果一个计算需要频繁进行,可以设计一个数据结构高效的处理这些计算需求。

6.4 Item M19 理解临时对象的来源
这里的临时对象是看不见的,不出现在源代码中。通常两种条件下会产生:
1为了使函数成功调用而进行的隐式类型转换。在任何时候只要见到常量引用(reference to const)参数,就存在建立临时对象而绑定在参数上的可能性。仅当通过传值方式传递对象或传递常量引用参数时,才会可能发生这些类型转换。当传递一个非常量引用参数对象,就不会发生:报错。
当程序员期望修改非临时对象时,对非常量引用(references-to-non-const)进行的隐式类型转换却修改临时对象。这就是为什么C++语言禁止为非常量引用(reference-to-non-const)产生临时对象。
2 函数返回对象时。在任何时候只要见到函数返回对象,就会有一个临时对象被建立。以某种方法返回对象,但不让编译器创建临时对象,这种技巧是返回constructor argument而不是直接返回对象(这叫:返回值优化):
return Rational(x,y);

6.5 Item M20 协助完成返回值优化
消除传值返回的对象的努力不会获得胜利,所以我们只能减小对象开销
1直接返回constructor argument而不出现局部对象
2通过声明函数为inline来消除operator调用开销

6.6 Item M21通过重载避免隐式类型转换
因为编译器完成这种隐式转换是有开销的,所以希望避免这种隐式的转换。
在C++中有一条规则是每一个重载的operator必须带有一个用户定义类型(user-defined type)的参数。

6.7 Item M22 考虑用运算符的赋值形式(op=)取代其单独形式(op)
这是因为赋值形式的效率要高:
1 operator的赋值形式比单独形式效率更高,因为单独形式要返回一个新对象,存在构造和释放的开销
2提供operator赋值形式的同时也要提供其标准形式,允许类的客户端选择
3不能在operator+里使用返回值优化

6.8 Item M23 考虑变更程序库
具有相同功能的不同程序库在性能上采取不同的权衡措施,所以一旦找到瓶颈,可考虑通过变更程序库提高效率

6.9 Item M24 理解虚拟函数,多继承,
虚拟函数,大多数编译器的实现是通过virtual table和virtual table pointers,分别被称为vtbl和vptr
vtbl是一个函数指针数组,程序中的每个类只要声明了虚函数或继承了虚函数,就有自己的vtbl,vtbl的项目是指向虚函数实现体的指针
vptr:每个声明了虚函数的对象都带有vptr,它是一个看不见的数据成员,指向对应类的virtual table
 
所以虚拟函数代价:
1必须为每个包含虚函数的类的virtual table留出空间(每个类有一个虚表), vtbl的大小与类中声明的虚函数的数量成正比(包括从基类继承的虚函数). 
采用启发式算法来决定哪一个object文件应该包含类的vtbl:要在一个object文件中生成一个类的vtbl,要求该object文件包含该类的第一个非内联、非纯虚拟函数。所以避免把虚函数声明为内联函数。
2在每个包含虚函数的对象里,必须为额外的指针付出代价
3放弃使用了内联函数: “内联”是指“在编译期间用被调用的函数体本身来代替函数调用的指令,”但是虚函数的“虚”是指“直到运行时才能知道要调用的是哪一个函数。”如果编译器在某个函数的调用点不知道具体是哪个函数被调用,你就能知道为什么它不会内联该函数的调用。所以内联和虚拟是互相矛盾的。(当通过对象调用虚函数时,它可以被内联,但是大多数虚函数是通过对象的指针或引用被调用的,需要函数生成实体和地址,所以这种调用不能被内联。因为这种调用是标准的调用方式,所以虚函数实际上不能被内联。)

通过指针pC1调用虚拟函数f1,编译器生成的代码会做如下这些事情:
1)通过对象的vptr找到类的vtbl,因此这个代价只是一个偏移调整(以得到vptr)和一个指针的间接寻址(以得到vtbl)。
2)找到对应vtbl内的指向被调用函数的指针,这步的代价只是在vtbl数组内的一个偏移。
3)调用第二步找到的的指针所指向的函数。
如果我们假设每个对象有一个隐藏的数据叫做vptr,而且f1在vtbl中的索引为i,此语句
pC1->f1(); 生成的代码基本就是这样的 (*pC1->vptr[i])(pC1);  
这几乎与调用非虚函数效率一样,调用虚函数所需的代价基本上与通过函数指针调用函数一样,本身不是性能的瓶颈。

多继承:
在多继承里,单个对象里有多个vptr(每个基类对应一个),为寻找vptr而进行的计算更为复杂

RTTI:和多态相关,因为运行时找到对象和类的相关信息,所以type_info对象存储了这些,通过typeid操作符访问类的type_info对象。语言规范上这样描述:我们保证可以获得一个对象动态类型信息,如果该类型有至少一个虚函数。所以,RTTI被设计为在类的vtbl基础上实现。使用这种实现方法,RTTI耗费的空间是在每个类的vtbl中的占用的额外单元再加上存储type_info对象的空间。

7 技巧
7.1 Item M25将构造函数和非成员函数虚拟化
虚拟构造函数是指能够根据输入给它的数据的不同而建立不同类型的对象,然而实际上它并不是真正的构造函数:真正的构造函数不可能做成虚拟的。虚拟拷贝构造函数只是调用它们真正的构造函数。
虚拟非成员函数的实现,是通过:public接口(可以内联) + private虚拟函数。非成员函数调用public接口。

7.2 Item M26 限制某个类所能产生的对象数量
(zhs)这里有一些理论不敢苟同,可以参照singleton的方法进行。

7.3 Item M27 要求或禁止在堆中产生对象
1)要求在堆中建立对象:(因为非堆对象在定义它的地方自动构造,在生存时间结束时自动被释放,因此禁止使用隐式的构造函数和析构函数就可以实现)。构造函数设为public,析构函数设为protected(既可以派生,还禁止了外部释放)。
2)判断一个对象是否在堆中:可以转化为判断是否能够删除一个指针,将new中得到的地址加入list中,通过查找可判断是否能删除指针。
3)把一个指针dynamic_cast成void*类型(或const void*或volatile void*等),生成的指针将指向“原指针指向对象内存”的开始处。但是dynamic_cast只能用于“指向至少具有一个虚拟函数的对象”的指针上。
上面是要求在堆上,下面是禁止在堆上。
“禁止在堆中建立对象”,三种情况:对象被直接实例化;对象做为派生类的基类被实例化;对象被嵌入到其它对象内。
1)声明operator new函数,而且为private,不但该类,连同派生类也被禁止了在堆中创建;
2)禁止堆对象 判断如果在堆中,则抛出一个异常

7.4 Item M28 智能指针
1, 1)智能指针从模板中生成,因为要与内建指针类似,必须是strongly type(强类型)的。
2)如ECpp所述,当auto_ptr被拷贝和赋值时,管理的对象可以有多种处理;如果对象所有权被传递,则函数要使用传引用而不是传值
3)实现*返回类型必须是引用:a)如果返回了一个基类对象而不是一个派生类对象的引用,会导致slicing问题; b)避免生成新的临时对象
4) 实现 -> 返回类型是内部对象的指针,或者是另外的一个智能指针
2,测试智能指针是否为NULL:共2种方法:
1)提供隐式类型操作符,用于这种目的类型转换的是void *:operator void*();
2)在智能指针中重载operator!,当且仅当智能指针是一个空指针时,operator!返回true.
3,除非有让人信服的原因,否则绝对不要提供转换到dumb指针的隐式类型转换操作符。
4,智能指针和继承类到基类的类型转换: SmartPtr<Cassette>向SmartPtr<MusicProduct>转换。在继承类向基类进行类型转换方面,我们如何能够让智能指针的行为与dumb指针一样呢?答案很简单:不可能。
5,智能指针和const
const SmartPtr<const CD> p = &goodCD;    // const 对象,const 指针
使用union支持const和非const两个指针,但是又不增加额外空间。
union { const T* constPointee;           // 让 SmartPtrToConst 访问
     T* pointee;                      // 让 SmartPtr 访问  };

7.5 Item M29 引用计数
1,引用计数是基于对象通常共享相同的值假设的优化技巧。目的:a) 简化跟踪堆中的对象的过程,是个简单的垃圾回收体系;b) 节省内存,提供性能(因为不需要构造和析构这个值的拷贝)
2,写时copy(copy on write):与其他对象共享一个值直到写操作时才拥有自己的copy.Lazy原则特例。保守地假设“所有”调用非const operator[]的行为都是为了写操作;当然所有const版本都是读
3,使用带有引用计数的基类,在内部使用智能指针来控制计数的增加和减少;
 
7.6 Item M30 代理类
代理类通常扮演其它对象的对象,通过代理类可以实现
1二维数组,Array1D扮演一维数组,是代理类。怎么实现?
2区分通过operator[]进行的是读操作还是写操作。通过修改operator[]让他返回一个proxy对象而不是字符本身
如果对左值来说,编译器努力的寻找一个隐式类型转换
如果对右值来说,赋值操作被调用
    CharProxy& operator=(const CharProxy& rhs);     // lvalue: s1[3] = s2[8]
    CharProxy& operator=(char c);                  // lvalue: s2[5] = 'x'
    operator char() const;                         // rvalue:cout << s1[5]
3限制了隐式类型转换

7.7 Item M31 让函数根据一个以上的对象来决定怎么虚拟
0)如果你需要实现二重调度,最好的办法是修改设计以取消这个需要。
1)一个操作,取决于两个对象的动态类型,使用一个对象的虚拟函数还不够。…

8杂项
8.1 Item M32 在未来时态下开发程序
提供完备的类,即使某些部分现在还没有被使用
将接口设计得便于常见操作并防止常见错误(E46),阻止拷贝构造和赋值操作如果类不需要(E27),防止部分赋值(M33)
8.2Item M33 将非尾端类设计为抽象类

8.3Item M34 如何在同一程序中混合使用C++和C
名变换:C++编译器给每个函数换一个独一无二的名字,因为C++引入了函数重载,但是C并不需要函数重载,如果要在C++里使用C函数,就要禁止名变换,使用C++的extern “C”指示: extern "C" void simulate(int iterations);
Extern “C”可以对一组函数生效: extern "C" {…}
静态初始化:在main执行前后都有大量的代码被执行,尤其是静态的类对象和定义在全局的、命名空间中的或文件中的类对象的构造函数通常在main被执行前调用(E47)。对应的析构函数在main结束运行之后。如果main不是C++写的,那么这些对象从来没对初始化和析构.
C99 标准中,只有以下两种定义方式是正确的: int main( void ); 和int main( int argc, char *argv[] );
C++98 中,如下两种 main 函数的定义方式:  int main( );    和int main( int argc, char *argv[] ); 
动态内存分配:总用delete释放new分配的内存,总用free释放malloc分配的内存
数据结构的兼容性:在C++和C之间相互传递数据结构是安全的,C++和C提供同样的编译。C++除了增加非虚成员函数不影响兼容性外,都影响兼容:虚函数,继承有基类的内容
 
8.4 Item M35 让自己习惯使用标准的C++语言
标准C++中STL中有三个概念:1容器(Container) 2迭代器(iterator)3算法(algorithm)
参考:http://www.diybl.com/course/3_program/c++/cppsl/200819/96109_2.html

转载于:https://my.oschina.net/u/256892/blog/371060

More effective C++学习总结相关推荐

  1. Effective C++ 学习笔记 第七章:模板与泛型编程

    第一章见 Effective C++ 学习笔记 第一章:让自己习惯 C++ 第二章见 Effective C++ 学习笔记 第二章:构造.析构.赋值运算 第三章见 Effective C++ 学习笔记 ...

  2. effective c++ 学习

    <Effective C++> 目录: 转自:http://blog.csdn.net/KangRoger/article/details/44706403 目录 条款1:视C++为一个语 ...

  3. Effective C++学习第十一天

    条款41:了解隐式接口和编译期多态 面向对象编程世界总是以显式接口(源码可见的接口)和运行期多态(virtual)解决问题:对于templates及泛型编程的世界,隐式接口和编译期多态显得更加重要: ...

  4. 【Effective C++ 学习笔记】

    条款02:尽量以const,enum,inline替换 #define #define定义的常量也许从未被编译器看见,也许在编译器开始处理源码之前它就被预处理器移走了: #define不重视作用域,不 ...

  5. Java:Effective java学习笔记之 考虑实现Comparable 接口

    Java 考虑实现Comparable 接口 考虑实现Comparable 接口 1.Comparable接口 2.为什么要考虑实现Comparable接口 3.compareTo 方法的通用约定 4 ...

  6. 侯捷 effective c++ 学习

    [别人的笔记](https://zhuanlan.zhihu.com/p/368047311) 本笔记为简略版,本人为了复习时看这些条款标题方便而做,觉得不详细可以看链接或者百度 第一部分 让自己习惯 ...

  7. Effective C++学习笔记(Part Five:Item 26-31)

    2019独角兽企业重金招聘Python工程师标准>>>  最近终于把effectvie C++仔细的阅读了一边,很惊叹C++的威力与魅力.最近会把最近的读书心得与读书笔记记于此, ...

  8. Effective C++ 学习笔记

    基于此文档 http://wenku.baidu.com/view/ef989106e87101f69e3195db.html 条款13:以对象管理资源 目标:为确保资源被释放 1.获得资源后立即放进 ...

  9. Effective C++学习笔记——构造/析构/拷贝运算

    条款9:决不再构造和析构过程中调用virtual函数,包括通过函数间接调用virtual函数. 应用:想在一个继承体系中,一个derived class被创建时,某个调用(例如生成相应的日志log)会 ...

最新文章

  1. 礼物——最牛午饭证!
  2. BUCK/BOOST电路原理分析
  3. MapInfo开发心得——多地图关联篇【转】
  4. 广东外语外贸大学计算机考研,广东外语外贸考研难度,2021考研广东外语外贸大学MTI会挤破头很难吗?...
  5. SQLi LABS Less 27 联合注入+报错注入+布尔盲注+时间盲注
  6. 人工智能火爆,入门却太难了!
  7. 获得执行计划方法三-sql_trace
  8. docker中运行mysql5.7,使用navicat链接报错10061/10060
  9. XSS绕过与防御总结
  10. 语音识别技术突飞猛进 终有一天将超过人
  11. php连接oracle数据库超详细教程
  12. 为什么浏览器全面禁用三方 Cookie
  13. Spark源码系列(二)RDD详解 - 岑玉海
  14. C++ 类设计规则及注意事项
  15. Mac 下 unrar 命令
  16. 关于微信表情及输入法emoji显示问题解决方案
  17. 刀片计算机学习资料第192篇:6U VPX i7 刀片计算机
  18. lightroom使用小结六 调整作品全局色彩
  19. 盘点HR日常工作数据计算大全
  20. python破解压缩密码.穷举.或弱密码

热门文章

  1. Python3 03 网络爬虫 <下载漫画>
  2. 捕获海康威视IPCamera图像,转成OpenCV可以处理的图像(一)
  3. 4、<VBA>学习用刘永富老师插件解析JSON格式数据
  4. javaweb失物招领网站源码
  5. RocketMQ生产者组topic和消费组的关系
  6. Xilinx Zynq UltraScale+ MPSoC 介绍
  7. 前端工作随笔日记 Day02
  8. 中学物理教学参考杂志社中学物理教学参考编辑部2022年第21期目录
  9. 品Spring:详细解说bean后处理器
  10. 安全尽职是企业的阿克琉斯之踵