编写高质量代码——“零星”总结(续2)

newdelete与new[]delete[]必须配对使用

//注意,由于内置数据类型没有构造、析构函数,所以针对内置数据类型时,释放和内存使用delete或delete[]的效果是一样的。

例如:

int *pArray = new int[10];

...//processing code

delete pArray;  //等同于delete[] pArray;

虽然针对内置类型,delete和delete[]都能正确地释放所申请的内存空间,但是如果申请的是一个数组,建议还是使用delete[]形式。

===================================

new内存失败后的正确处理

//新的标准里,Test-for-NULL处理方式不再被推荐和支持:抛出一个bad_alloc exception (异常)

//推荐使用 try{ p = new int[SIZE]; } catch ( std::bad_alloc ) { ... }

//只有负责内存申请的 operator new 才会抛出异常 std::bad_alloc。

===================================

new内存失败后的正确处理

了解new_handler的所作所为

借助工具监测内存泄漏问题

小心翼翼地重载operator new operator delete

用智能指针管理通过new创建的对象

===================================

使用内存池技术提高内存申请效率与性能

//当程序中需要对相同大小的对象频繁申请内存时,常会采用内存池(Memory Pool)技术来提高内存申请效率,减少内存碎片的产生。

----------------------------------

//基本原理(“池”):应用程序可以通过系统的内存分配调用预先一次性申请适当大小的内存块(Block),并且将它分成较小的块(Smaller Chunks),之后每次应用程序会从先前已经分配的块(chunks)中得到相应的内存空间,对象的分配和释放的操作都可以通过这个“池”完成。只有当“池”的剩余空间太小,不能满足应用程序需要时,应用程序才会在调用系统的内存分配函数对其大小进行动态扩展。(和malloc差不多,进行一次的系统调用,分配33页,不够再申请)

----------------------------------

//经典的内存池实现原理:指针变量pMem把所有申请的内存块(MemBlock)串成一个链表。指针变量pFree把所有自由的内存结点(FreeNode)串成一个链表。 内存块在申请之初就被划分为了多个内存结点,每个结点的大小为ItemSize(对象的大小),共计MemBlockSize/ItemSize个。

//每次分配的时候从MemBlock链表中取一个结点给用户,不够时继续向系统申请大块内存。

//在释放内存时,只须把要释放的结点添加到自由内存链表pFree中即可。

//在MemPool对象析构时,可完成对内存的最终释放。

===================================

明晰class与struct之间的区别

//面向过程的编程认为,数据和数据操作应该是分开的。

//面向对象的C++认为,数据和数据的操作是一个整体。

===================================

了解C++悄悄做的那些事

//所有的类都有着一个类似的中枢骨干(“Big Three”):一个或多个构造函数 + 一个析构函数 + 一个拷贝赋值运算符

//=delete        =default

//对于类,编译悄悄完成的事:隐式产生默认构造函数、拷贝构造函数、拷贝赋值运算符和析构函数。

//为了能够实例化,编译器“强制”使其大小由 0 变成 1。

===================================

明智地拒绝对象的复制操作

//禁止对象复制操作(拷贝构造函数 和 赋值操作符):

方式一、通过类的访问控制private(一方面阻止了编译器越俎代庖的声明和定义,另一方面禁止对复制操作函数的显示调用)

如下:

class CStudent{

public :

...

private :

CStudent ( const  CStudent&  other );

CStudent operator=( const  CStudent&  rhs );

}//但是,成员函数和友元函数仍可以访问,C++赋予了它们调用 private 成员函数的权利。

---------------------------------

方式二、只声明不定义,那么成员函数和友元函数对它们的调用,编译器会明令禁止(声明而不定义成员函数是合法的,但是使用未定义成员函数的任何尝试将导致链接失败),即实现了类复制的完全禁止。

================================

小心,自定义拷贝函数(拷贝构造函数和赋值运算符)

//自定义拷贝函数是一种良好的编程风格,可以阻止编译器形成默认的拷贝函数,但应该保证拷贝一个对象的 All Parts:所有数据成员及所有的基类部分。

==========

======================

多态基类的析构函数应该为虚

//C++中指出:当一个派生类对象通过使用一个基类指针删除,且这个基类有一个非虚的析构函数时,C++将不会调用整个析构链,只是调用了基类的析构函数,即“部分析构”。

--------------------------------

//解决:将基类的析构函数设置为虚,用基类指针删除一个派生类对象时,C++会正确地调用整个析构链,销毁整个对象。

--------------------------------

//使用虚析构函数要遵守的原则:(基)类中至少有一个虚函数。反之,如果类中有虚函数,它就该有一个虚析构函数。

//如果一个类不包含虚函数,不要将析构函数声明为虚。因为虚函数的实现要求对象携带额外的信息,会导致对象的大小增加。

--------------------------------

//普通继承:自动调用基类和派生类的析构函数。

//多态:有多态,基类一定有虚成员函数,有虚成员函数,析构函数就要声明为virtual。

================================

绝不让构造函数为虚

//假设构造函数是虚函数,那么就需要通过虚函数表来调用应该调用的函数,但此时面对的是一块 raw 内存,虚函数表尚未建立,不能支持虚函数机制(虚函数表由构造函数建立),故构造函数不能为虚函数。

================================

默认参数在构造函数中给你带来的喜与悲

//如果不合理的使用默认参数,将会导致重载函数的二义性。

【好烦CSDN的字体问题a】

编写高质量代码——“零星”总结(续2)

时间: 2024-08-03 20:26:30

编写高质量代码——“零星”总结(续2)的相关文章

编写高质量代码——“零星”总结(续3)

明白在C++中如何使用C C++中使用C的程序库,实现C++和C的混合编程:extern "C" { /* code */ }一定要加在C++的代码文件中才能起作用. //C编译器编译函数时不带函数的类型信息,只包含函数符号名字:而C++编译器为了实现函数重载,在编译时会带上函数的类型信息.extern "C"的作用:告诉C++链接器寻找调用函数的符号时,采用C的方式. =================================== 使用memcpy()系列

编写高质量代码——“零星”总结

不要让main函数返回void //在C++中绝对没有出现过 void main(){  }这样的函数定义,在C语言中也是. //两种 main 的定义方式:int main( void ); //                     int main( int argc, char** argv ) //第一版的C语言中只有 int 一种数据类型,为了兼容 需要,不明确标明返回值的,默认为 int //在main函数中,return 语句的作用在于离开main函数(析构掉所有具有动态生存时

每周一书-编写高质量代码:改善C程序代码的125个建议

首先说明,本周活动有效时间为2016年8月28日到2016年9月4日.本周为大家送出的书是由机械工业出版社出版,马伟编著的<编写高质量代码:改善C程序代码的125个建议>. 编辑推荐 10余年开发经验的资深C语言专家全面从C语法和C11标准两大方面深入探讨编写高质量C代码的技巧.禁忌和实践 C语言因为既具有高级语言特性,又具有汇编语言特性,所以它是近二十几年来使用较为广泛.生命力较强的编程语言.无论是操作系统.嵌入式系统.普通应用软件,还是移动智能设备开发,它都能够很好地胜任,是公认的强大的语

代码质量优先——《编写高质量代码:改善c程序代码的125个建议》

高质量的代码不但可以促进团队合作.减少bug处理.降低维护成本,对程序员自身的成长也是至关重要的.很难想象一个参考<如何编写无法维护的代码>写代码的程序员技术成长的上限有多么低.为了写出高质量的代码,我们需要听取过来人的改善代码质量的经验,<编写高质量代码:改善c程序代码的125个建议>就是一本能让人写出高质量代码的好书. 本书的第三章<程序控制语句应该保持简洁高效>首先用简练的语言介绍了流程控制结构的概念,然后提供了对if.else.for.do-while.swit

[ 转 ]编写高质量代码:改善Java程序的151个建议

记得3年前刚到公司,同桌同事见我无事可做就借我看<编写高质量代码:改善Java程序的151个建议>这本书,当时看了几页没上心就没研究了.到上个月在公司偶然看到,于是乎又找来看看,我的天,真是非常多的干货,对于我这种静不下心的人真是帮助莫大呀. 看完整本书,也记了不少笔记,我就分享一部分个人觉得有意义的内容,也为了方便以后自己温习. --警惕自增陷阱 i++表示先赋值后自增,而++i表示先自增后赋值.下面的代码返回结果为0,因为lastAdd++有返回值,而返回值是自增前的值(在自增前变量的原始

编写高质量代码改善C#程序的157个建议——建议45:为泛型类型参数指定逆变

建议45:为泛型类型参数指定逆变 逆变是指方法的参数可以是委托或者泛型接口的参数类型的基类.FCL4.0中支持逆变的常用委托有: Func<int T,out TResult> Predicate<in T> 常用委托有: IComparer<in T> 下面例子演示了泛型类型参数指定逆变所带来的好处: class Program { static void Main() { Programmer p = new Programmer { Name = "Mi

编写高质量代码改善C#程序的157个建议——建议27:在查询中使用Lambda表达式

建议27:在查询中使用Lambda表达式 LINQ实际上是基于扩展方法和Lambda表达式的.任何LINQ查询都能通过扩展方法的方式来代替. var personWithCompanyList = from person in personList select new { PersonName = person.Name, CompanyName = person.CompanyID==0?"Micro":"Sun" }; foreach (var item in

编写高质量代码改善C#程序的157个建议——建议26:使用匿名类型存储LINQ查询结果

建议26:使用匿名类型存储LINQ查询结果 从.NET3.0开始,C#开始支持一个新特性:匿名类型.匿名类型有var.赋值运算符和一个非空初始值(或以new开头的初始化项)组成.匿名类型有如下基本特性: 即支持简单类型也指出复杂类型.简单类型必须是一个非空初始值,复杂类型则是一个以new开头的初始化项. 匿名类型的属性是只读的,没有属性设置器,它一旦被初始化就不可更改. 如果两个匿名类型的属性值相同,那么就认为这两个匿名类型相等. 匿名类型可以再循环中用作初始化器. 匿名类型支持智能感知. 匿名

编写高质量代码改善C#程序的157个建议——建议20:使用泛型集合代替非泛型集合

建议20:使用泛型集合代替非泛型集合 在建议1中我们知道,如果要让代码高效运行,应该尽量避免装箱和拆箱,以及尽量减少转型.很遗憾,在微软提供给我们的第一代集合类型中没有做到这一点,下面我们看ArrayList这个类的使用情况: ArrayList al=new ArrayList(); al.Add(0); al.Add(1); al.Add("mike"); foreach (var item in al) { Console.WriteLine(item); } 上面这段代码充分演