Effective C++ 条款 50:了解new和delete的合理替换时机

(一)

为什么有人想要替换operator new 和 operator delete呢?三个常见的理由:

(1)用来检测运用上的错误。

(2)为了强化效果。

(3)为了收集使用上的统计数据。

(二)

下面是个快速发展得出的初阶段global
operator new,促进并协助检测“overruns”或“underruns”。

static const int signature = 0xDEADBEEF;
typedef unsigned char Byte;
void* operator new(std::size_t size) throw(std::bad_alloc) {
	using namespace std;
	size_t realSize = size + 2 * sizeof(int);
	void* pMem = malloc(realSize);
	if(!pMem) throw bad_alloc();
	//将signature写入内存的最前段落和最后段落
	*(static_cast<int*>(pMem)) = signature;
	*(reinterpret_cast<int*>(static_cast<Byte*>(pMem)+realSize-sizeof(int))) = signature;
	return static_cast<Byte*>(pMem) + sizeof(int);
}

这个operator new的主要缺点在于疏忽了身为这个特殊函数所应该具备的“坚持c++规矩”的态度。条款51说所有operator new都应该内含一个循环,反复调用某个new_handling函数,这里却没有。这儿我们暂且忽略之。现在只想专注一个比较微妙的主题:alignment(齐位).

(三)

齐位,对齐方式。

许多计算机系统要求特定的类型必须放在特定的内存地址上。例如可能会要求指针地址必须是4倍数(four-byte aligned)或double是的地址必须是8倍数。如果没有奉行这个条件,可能导致运行期硬件异常。有些系统结构比较慈悲,而是宣称如果齐位条件获得满足,便提供较佳效率。例如Intel
x86体系结构上doubles可以对齐于任何byte边界,但如果他是8-byte齐位,其访问速度会快很多。(个人理解,没有对齐的话,微处理器的读取指针在每次读取数据的时候都要事先加上offset,所以会影响速度)

c++要求所有的operator news返回的指针都有适当的对齐(取决于数据类型),malloc就是在这样的要求下工作,所有operator new返回一个malloc的指针是安全的。然而,我们返回的是一个得自malloc且偏移一个int大小的指针。没人保证它的安全。如果客户端调用operator
new企图取得足够一个double所用的内存,而我们在一部“ints为4bytes且double必须8bytes齐位”的机器上跑,我们可能会获得一个未有适当齐位的指针。那可能会造成程序崩溃或速度变慢。

(四)

何时可在“全局性的”或“class专属的”基础上合理替换缺省的new和delete:

(1)为了检测运用错误。

(2)为了收集动态分配内存的使用统计信息。

(3)为了增加分配和归还的速度。

(4)为了降低缺省内存管理器带来的额外空间开销。

(5)为了弥补缺省分配器中的非最佳齐位(suboptimal
alignment)。

(6)为了将相关对象成簇集中。

(7)为了获得非传统行为。

请记住:

(1)有许多理由需要写个自定的new和delete,包括改善效能、对heap运用错误进行调试、收集heap使用信息。

时间: 2024-11-25 05:36:31

Effective C++ 条款 50:了解new和delete的合理替换时机的相关文章

Effective C++ 条款50 了解new和delete的合理替换时机

1. 替换标准库提供的operator new或operator delete通常基于以下三个理由: 1). 用来检测运行上的错误.将"new 所得内存"delete掉却不幸失败会导致内存泄露,多次对同一块"new所得内存"施行delete会导致未定义行为,如果让operator new持有一串动态分配所得地址,而operator delete将地址从中移走,就可以很容易检测出上述错误;各式各样的变成错误会导致数据"overruns"(写入点在分

Effective C++ 条款50

了解new和delete的合理替换时机 如题所述,我们在本节中只是了解一下什么时候需要自己写new和delete,为什么要重新写new和delete,出于什么样的动机等等. 本文重在论述,至于作者提供的程序代码也具有漏洞,本节的目的就是对new和delete有一个宏观的认识. 下面是替换的原因: 1.用来检测运用上的错误.如果delete new的内存失败,会导致内存泄漏.如果在new所得内存多次delete会导致不确定行为.使用编译器提供的operator new和operator delet

《Effective C++》:条款50:了解new和delete的合理替换时机

有人会想要替换掉编译器提供的operator new或operator delete,因为 用来检测运用上的错误.如果delete new的内存失败,会导致内存泄漏.如果在new所得内存多次delete会导致不确定行为.使用编译器提供的operator new和operator delete不能检测上述行为.如果operator new持有一个链表,其存储动态分配所得内存,operator delete则将内存从链表删除,这样就能呢检测上述错误用法.如果编程错误,可能在分配内存的之前区域或之后区

Effective C++ 条款51 编写new和delete时需固守常规

1. 实现定制的operator new和operator delete需要满足一定的要求. 以operator new而言:实现一致性operator new必须返回正确的值;内存不足时必得调用new-handling函数;必须有对付零内存需求的准备;需避免不慎掩盖正常形式的new;如果有能力供应客户申请的内存,就返回一个指针指向该内存,反之就遵循条款49的规则并抛出bad_alloc异常;应该内含一个无限循环,知道成功分配内存或new-handling完成其功能...... 以上的要求中"必

Effective C++ 条款15、16 在资源管理类中提供对原始资源的访问||成对使用new 与 delete要采取相同形式

1.在资源管理类中提供对原始资源的访问     前几个条款很棒,它们是对抗资源泄露的壁垒,但很多APIs直接指向 资源,这个时候,我们需要直接访问原始资源.     这里,有两种方法解决上述问题,我们可将RAII对象转换为原始资源.通过 显式转换与隐式转换.     通常,tr1:: shared_ptr 和 auto_ptr 都提供一个get成员函数,用来执行显式转换,也就是返回智能指针内部的原始指针的复件.因为它也重载了指针取值操作符* –>.当然也可以通过隐式转换为底部原始指针.     

More Effective C++ 条款35 让自己习惯于标准C++ 语言

(由于本书出版于1996年,因此当时的新特性现在来说可能已经习以为常,但现在重新了解反而会起到了解C++变迁的作用) 1. 1990年后C++的重要改变 1). 增加了新的语言特性:RTTI,namespaces,bool,关键词mutable和explicit,enums作为重载函数之自变量所引发的类型晋升转换,以及"在class 定义区内直接为整数型(intergral) const static class members设定初值"的能力. 2). 扩充了Templates的特性

More Effective C++ 条款34 如何在一个程序中结合C++和C

1. C++和C混合使用的前提之一就是编译器产生兼容的目标文件(.lib和.dll等).所谓"兼容",指的是编译器在"预编译器相依的特性上"一致,如int和double大小,参数压栈机制等,只有在这个基础上才能讨论结合使用C++和C模块的问题. 2. 在1的基础上,要结合使用C++和C的模块,主要有以下几点需要注意: 1). name mangling(名称重整) Name mangling是C++用于支持函数重载的机制,它对重载的函数名称进行一定改变,使得每个函数

effective c++ 条款13 use object to manage resources.

请求的系统资源需要最终还回系统,为了避免遗忘返还这个动作,可以利用析构函数在object销毁时自动调用的特点来实现. 简单说就是用object来管理资源. 以内存资源为例 class Investment {}; Investment* creatInvestment(){...} // factory function to produce investment object void main() { Investment* pInv = creatInvestment();//call t

Effective C++ 条款11,12 在operator= 中处理&ldquo;自我赋值&rdquo; || 复制对象时不要忘记每一个成分

1.潜在的自我赋值     a[i] = a[j];     *px = *py; 当两个对象来自同一个继承体系时,他们甚至不需要声明为相同类型就可能造成别名. 现在担心的问题是:假如指向同一个对象,当其中一个对象被删,另一个也被删,这会造成不想要的结果. 该怎么办? 比如:   widget& widget:: operator+ (const widget& rhs) {    delete pd;    pd = new bitmap(*rhs.pb);    return *thi