编写高质量代码之改善C++程序语法篇3


阅读《编写高质量代码--改善C++程序的150个建议》,总结归纳;


    此文用以加深记忆,督促学习的目的


在线阅读http://book.51cto.com/art/201202/317549.htm


0 区分内存分配的方式

内存管理的水平是衡量高手和菜鸟的一个不成为的约定


一个程序加载到计算机内存里,可形成一个运行空间,大致分为:代码区、数据区、堆区、栈区

  * 代码区:存放的是程序的执行代码

  * 数据区:存放的是全局数据、常量、静态变量等

  * 堆区:存放的是动态内存,供程序使用

  * 栈区:存放的是程序中所用到的局部数据


  + 代码区是我们不能在代码中控制的,其他三个区是编码过程中利用的

  + 数据区自由存储区、全局/静态存储区和常量存储区

  + 自由存储区:是有malloc等分配的内存块,需要使用free来释放

  + 全局/静态存储区: 全局变量和静态变量被分配到同一块内存中

  + 常量存储区: 存放常量,不允许修改



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


   * delete删除对象时,编译器只会将指针所指向的对象当作单个对象来处理



1  区分new的三种形态

  * new operator

    这是我们使用最多的

    

string *pStr = new string("Memory Management");  
int *pInt = new int(2011); 

  * operator new

class A  
{  
public:  
     A(int a);  
     ~A();  
     void* operator new(size_t size);  
 ...  
};  
void* A::operator new(size_t size)  
{  
 cout<<"Our operator new...");  
 return ::operator new(size);  
} 


  * placement new

   placement new是用来实现定位构造的,可以通过它来选择合适的构造函数。虽然通常情况下,构造函数是由编译器自动调用的,但是不排除你有时确实想直接手动调用,比如对未初始化的内存进行处理,获取想要的对象,此时就得求助于一个叫做placement new的特殊的operator new了

#include  
#include "ClassA.h"  
int main()  
{  
     void *s = operator new(sizeof(A));  
 A* p = (A*)s;  
 new(p) A(2011);  //p->A::A(2011);  
 ... // processing code  
     return 0;  
} 

总结一下:

如果是在堆上建立对象,那么应该使用 new operator,它会为你提供最为周全的服务。

如果仅仅是分配内存,那么应该调用operator new,但初始化不在它的工作职责之内。如果你对默认的内存分配过程不满意,想单独定制,重载operator new 是不二选择。

如果想在一块已经获得的内存里建立一个对象,那就应该用placement new。但是通常情况下不建议使用,除非是在某些对时间要求非常高的应用中,因为相对于其他两个步骤,选择合适的构造函数完成对象初始化是一个时间相对较长的过程



2 new内存失败后的正确处理

当使用new申请一块内存失败时,抛出异常std::bad_alloc是C++标准中规定的标准行为,所以推荐使用try{ p = new int[SIZE]; } catch( std::bad_alloc ) { ... }的处理方式。但是在一些老旧的编译器中,却不支持该标准,它会返回NULL,此时具有C传统的Test_for_NULL代码形式便起了作用。所以,要针对不同的情形采取合理的处置方式。



3 了解new_handler的所作所为

通常,一个好的new-handler函数的处理方式必须遵循以下策略之一:
Deinstall the new-handler(卸载new-handler)
Make more memory available(使更大块内存有效)

Install a different new-handler(装载另外的new-handler)

Throw an exception(抛出异常)

Not return(无返回)

直接调用abort或exit结束应用程序。




4 借助工具检测内存泄露问题


   * linux下的Valgrind和Rational Purify



5 小心翼翼的重载operator new/ operator delete


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


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


经典的内存池实现原理如下:

class MemPool  
{  
public:  
 MemPool(int nItemSize, int nMemBlockSize = 2048)  
    : m_nItemSize(nItemSize),  
    m_nMemBlockSize(nMemBlockSize),  
    m_pMemBlockHeader(NULL),  
    m_pFreeNodeHeader(NULL)  
  {  
  }  
  ~ MemPool();  
  void* Alloc();  
  void  Free();  
private:  
   const int m_nMemBlockSize;  
   const int m_nItemSize;  
 
   struct _FreeNode  
   {  
       _FreeNode* pPrev;  
       BYTE data[m_nItemSize - sizeof(_FreeNode*)];  
   };  
 
   struct _MemBlock  
     {  
       _MemBlock* pPrev;  
       _FreeNode data[m_nMemBlockSize/m_nItemSize];  
     };  
 
   _MemBlock* m_pMemBlockHeader;  
   _FreeNode* m_pFreeNodeHeader;  
 
}; 

Boost库同样对该技术提供了较好的支持:

 
  
  1. pool(#include <boost/pool/pool.hpp>)  
  2. boost::pool用于快速分配同样大小的小块内存。如果无法分配,返回0,如下所示。  
  3. boost::pool<> p(sizeof(double)); //指定每次分配块的大小  
  4. if(p!=NULL)  
  5. {  
  6.      double* const d = (double*)p.malloc(); //为d分配内存  
  7.      pA.free(d);   //将内存还给pool  

pool的析构函数会释放pool占用的内存。




你可能感兴趣的:(C++,笔记,C++,高质量)