逻辑设计问题 -- 实现一个对象

实现一个对象

数据成员

自然对其

如果一个基本类型实例的大小能整除其地址值,那么它是自然对齐的

一个聚集类型的实例,如果其对其要求最严格的子类型的排列能整除聚集的地址,那么它是自然对齐的

声明数据成员的次序能够影响对象的大小

在实现中使用的基本类型

只有在已知这样做安全时,才能为了优化在实现中使用sort替代int

即使在实现中也尽量不要考虑使用unsigned

在实现中使用unsigned类型以提高一点性能,是基本的整数类型没有大到足够安全的标志

在实现中使用typedef

typedef 通常能够帮助表达复杂的函数声明。在某些采用精确位数表示的基本类型的定义中,typedef也是非常有用的

函数定义

自我断言

将函数行为无定义的条件建成文档是开发接口的一个重要的部分。在接口中进行注释是消极的,并且不会再运行时发出程序出错的警告。我们可以结合使用注释和assert语句来得到 轻量级的可维护代码

避免特殊情况

自然地包括其边界条件算法,通常比将边界条件作为特殊情况处理的算法更简单、更短小、更易于理解和测试

通过增加一个额外的间接层能解决很多的问题

用分解代替副本

一个组件中分解出一般可重用的功能,可以减少代码长度并且提高可靠性,而不会损失太多的运行时性能

不要过于聪明

在设计一个函数、组件、包或完整的系统是偶,使用最简单的有效的技术

内存管理

高性能设计的一个重要方面就是内存管理。在一定情况下,通过在更严格的上下文中进行内存分配,能获得真实的性能收益。同时,内存是全局资源;个别类不恰当地使用内存管理(如过分地使用内联函数),将对继承系统性能产生负面影响

逻辑或者物理状态值

如果一个和某对象状态相关的值有助于预期的语义,那么它是逻辑值;否则就是物理值

对一个完全封装的接口来说,每个可编程访问的值都是一个逻辑值

逻辑值是根据语义而不是通过程序可访问能力来定义的,这是因为封装经常被以效率高的名义破坏。仅仅因为一个对象在实践中未能封装一个特定的值,并不能判定它有助于基本的行为。虽然一个组件开发者的意图没有通过组件接口能访问的值那样易于客观度量,但是这个基本行为倾向于不像依赖程序访问值的集合那样依赖实现选择

避免允许通过程序对物理值进行访问

提示是只写的,最好的提示不直接被绑定到特定的实现

调用一个const成员函数的结果不应该改变对象中的任何可编程访问的值

如果一个支持值语义的类型有两个实例,两个实例各自所有的逻辑值都相等,那么这两个实例是相等的;只要有任何一个单一的逻辑值不相等,这两个实例就是不相等的

内存分配器

将全局运算符new和delete工具化,是在系统中理解和测试动态内存分配行为的简单有效的方法

复杂的内存分配器的一个共同特性是:复杂并极易出错,但他们都有使其难于测试且测试开销都很大的微小接口。幸运的是,作为程序开发者,我们有主程序。因此,我们知道总是能够利用重新定义全局的new和delete来满足我们的要求

当我们使用全局的new和delete的时候,使用iostream会引起令人不愉快的副作用

因为iostream使用了全局的运算符new,所以当重定义全局运算符new时,我们希望避免使用iostream。回归到使用更基本的stdio,可以避免在工具化全局运算符new和delete时的递归

特定类内存管理

C++语言允许我们在逐个类的基础上,通过重新定义特定的类的运算符new和delete来接管所有动态内存分配过程。任何人如果分配类的动态实例,将自动接到一个指向由特定类分配器所提供的内存的指针

独占内存

定制的特定类的分配器常常存在以下问题:他们往往是在整个程序的执行期间收集内存,但是它们从不将内存返还给全局分配器

从不返还其内存的特定类的分配方案,使得对内存泄漏的自动检测变得更加困难

特定类的内存分配器倾向于占用全局分配的内存,因此增加了整个内存的使用

对特定类的内存管理方法不加选择的使用,是一种自我为中心的形式,它会对一个集成系统的整体性能产生负面影响

特定对象内存管理

类的独立实例应有独立行为。这个观念既可以用于功能方面,又可以用于组织方面。特定类的内存管理方法不知道什么时候删除其缓冲池的一部分是安全的。另一方面,每个客户对象都知道将应用从属对象的上下文,这样就可以更清楚的知道什么时候不再需要它们。

一个特定对象的内存分配方案有足够的上下文可以知道什么时候不再需要一些实例的子集而可以释放它们(这些实例子集是分配给特定对象并由它来管理的)

特定对象的内存管理比特定类的内存管理要好

使用一个非const指针数据成员来保存被管理的对象

避免依赖一个和对象再初始化过程中定义数据成员的顺序

如果我们能利用有关特定用户使用模式的知识,我们通常可以为其管理的对象编写更有效的分配程序

考虑提供一种方法再块分配和动态内存的单独分配之间进行切换

当程序失去了对动态内存块进行释放的能力时会发生内存泄漏

在大型工程中使用C++模板

编译器实现

大多数编译器使用以下两种方式之一实现模板:

  • CFRONT型:当程序中遇到模板时候,创建一个系统级的库,以提供编译单元共享的信息
  • MACRO型:用户必须可以使用模板组件的头部分和实现部分的源代码

在模板中管理内存

编写一个好的模板容器类比为一个特定的对象编写一个等价的容器类要困难的多。在编写模板时,我们必须注意到参数类型到参数类型可以是基本数据类型,也可以是自我管理动态内存的用户自定义类型。从一个基本类型中直接派生是不可能的,一般也不可能使用位拷贝(如memcpy)来移动用户自定义类型。

通过在一个伪参数化类型中嵌入实际参数类型,我们可以在继承方面像处理用户自定义类型那样处理基本类型,并且允许它有寻址和分配的功能,这些功能在用户自定义类型中都是没有的

一般来说一个对象不能使用位拷贝来拷贝或者移动

一般来说,不能使用对象的赋值运算符将对象拷贝或者移动到未初始化的内存

当为一个通用的、参数化的容器模板实现内存管理时,若赋值的目标是未初始化的内存,则要小心不要使用被包含类型的赋值运算符

当为一个完全通用的、参数化的容器类实现内存管理时(该容器类管理其包含对象的内存),假定参数化类型只定义了拷贝构造函数和析构函数–别无其它

只有使用其拷贝构造函数才能合理地拷贝一个任意对象。要移动和一个任意对象只能通过先使用其拷贝构造函数,然后显式地调用其析构函数才行

尽可能,在分解的可重用的void * 指针类型的顶部,使用内联函数来实现模板,以重建类型的安全性

模式与模板

设计模式时类或者对象的抽象组织,它被反复证明在解决多领域的相似问题上是有效的

设计模式是在体系结构层次上交流可重用概念和思想的有效方法

设计模式与设计过程自身一样,能处理逻辑和物理问题

小结

对齐需求能导致在对象的物理布局中出现空隙。重新安排内部数据有时候能够减小实例大小,者对于希望在一个时刻有多个实例的类来说非常重要。

在最小化对象规模的工作中,我们有时候会使用short或者char基本类型代表整数数据成员,但只有当我们确定不会发生溢出的时候才可以这么做。试图使用unsigned得到额外的位,这样做说明整数类型还没有大到足够安全的底部。总的来说,使用unsigned易于出错,不予推荐。

typedef声明能够被用作特定大小的基本类型的别名,这些基本类型取特定大小是为了使各个平台的对象实现保持一致性,如在面向对象数据库中所做的那样

在实现个别功能的层次上,做出错误决策的代价相对较小,因为这种决策的影响通常局限在系统的很小一部分当中。但是下面的做法是被推荐的:

  • 使用assert语句来帮助确认你在整个复杂功能的实现中做出的假设并建档
  • 尽量将边界条件融入到基本算法中,而不是将其作为特殊情况对待
  • 在单个组件中,尽可能避免重复代码块;而是将这些代码块重新分解为局部的可重用子程序
  • 一般来说,尽量寻找能有效解决问题的最简单的方法

逻辑状态值有助于一个对象的基本行为,而物理状态值只是特定实现选择的一个技巧。作为一个规则,我们应该努力避免提供对物理值的编程访问

提示是客户使对象改善性能而向该对象提供的附加信息。就像inline或者register,提示仅仅是一种建议,不应该影响一个对象的逻辑状态。

定制的动态内存管理实现起来可能很复杂,但是对获得高性能又经常使必要的。管理动态分配内存的设计空间可以相当大。又以下扩大一个内部数组规模的两种方式:

  • GROW_FACTOR:通过乘法因子增大数组规模(首选)
  • GROW_SIZE:通过加入一个固定增量来增大数组规模

两种内存分配器:

  • 块分配器:追踪大小潜在变化的每个分配块,并且提供一种机制,一旦不再需要内存时,将其全部回收
  • 缓冲池分配器:保持固定大小块的自由缓冲池。当池为空时,调用块分配器来补充缓冲池。当缓冲池被析构时,所有块被回收

我们观察到通过工具化全局运算符new和delete来开发和使用内存分配器又很多好处。注意,我们将全局内存运算符函数体中使用stdio.h文件中的声明功能,而不是iostream文件中的声明,因为iostream依赖全局new运算符来进行它自己的动态分配

特定类内存分配意味着类本身包含静态变量,以帮助管理实例化对象的内存,这常常是通过保留一列未使用的内存块来实现的,这些内存的大小适合该特定对象。这种优化的结果使运行时性能翻倍并非不寻常。

模板是C++语言表示能力的重要部分。很多已有的编译器实现有严重的缺陷:要么连接时间过长,要么它们的实现不能与客户程序绝缘。STL的采用对编译器提出了更高的要求,要求它对大型项目中的模板提供有效和健壮的支持

  • 13
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

turbolove

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值