`
congfeng02
  • 浏览: 200058 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

在预先定义的内存位置构造一个对象

 
阅读更多

在预先定义的内存位置构造一个对象

赵湘宁

常常有人问这样一个C++问题:如何在预先定义的内存位置构造一个对象?在预先定义的内存缓冲构造一个对象有许多有用的应用。例如,一个定制的垃圾搜集器能使用一个大的预分配内存缓冲,用户在这个缓冲中构造其对象。当不再需要这些对象时,它们的存储空间被自动收回。
这个技术在重视时间的应用中也很有用。在预先分配的内存缓冲构造一个对象是一种“时间常量”操作,之所以这样说是因为程序分配操作本身不会浪费宝贵的时间。同时也要注意当系统没有足够的内存时,动态内存分配可能失败。因此,对于重视任务的应用,预先分配一个足够大的缓冲有时是不可避免的。
许多应用需要在给定的时间构造不同类型的对象。想一想这样一个例子,一个GUI应用根据用户的输入,每次、显示不同的对话框,利用重复分配和释放内存,这个应用能提前创建一个内存缓冲,并能在这个缓冲里反复构造和销毁不同类型的对象。
C++提供了几种特点来方便实现在预先决定的内存位置构造一个对象的任务。在这些特点中,包括一个特殊形式的new操作符,叫做“定位new”(placement new)操作,以及一个显式的析构处理。实现方法如下:
第一步:分配一个足够的内存缓冲区,以便存放给定类型的对象。如果想要每次构造不同类型的对象,需要至少以最大的对象所占空间的大小分配一个缓冲。预分配的缓冲是在可用内存空间中分配的纯字符数组。
        char * buff = new char [sizeof (Foo) ];  
一旦分配了缓冲,就能在缓冲中构造每一种类型的对象。为此,使用特殊版本的new操作符(“定位new”),以缓冲地址为placement new的参数。为了使用placement new,必须包含标准头文件<new>。下面的代码片断中,使用placement new操作在内存地址buff上构造类型为Foo的对象。
        #include <new>
        Foo * pfoo = new (buff) Foo; //使用new操作在buff上构造一个 Foo  
Placement new 以先前分配的缓冲(buff)地址作为参数,并在这个缓冲上构造给定类型的对象。他返回构造对象的指针,这个对象指针的使用与通常的指针使用没什么两样。
        unsigned int length = pfoo->size();
        pfoo->resize(100, 200);
        length = pfoo->size();  
当不再需要这个对象的时候,必须显式调用其析构函数释放空间。做这件事是有一些技巧的,因为许多人错误地假设对象会被自动销毁,错也!。在预分配的缓冲里构造另一个对象之前或者在释放缓冲之前,如果忘了显式调用析构函数,程序将产生不可预料的后果。显式的析构器声明如下:
        pfoo->~Foo(); //显式调用析构函数  
换句话说,一个显式的析构器与普通的成员函数调用一样,只是名字与普通的成员函数稍有差别。一旦对象被销毁,便可以在预分配的内存中再次构造另一个对象。实际上,这个过程可以无限制地重复:构造一个对象,销毁它,然后又反复利用预分配的缓冲构造新对象。
当不再需要预定义的缓冲时,或者说当应用程序关闭时,必须释放预定义的缓冲。使用delete[]完成这个任务,因为预定义的缓冲是一个字符数组。下列代码包含一个完整的例子的所有步骤,包括最终缓冲的释放:
#include <new>

  void placement_demo()
  { 
    //1. 预分配缓冲
    char * buff = new char [sizeof (Foo) ];  

    //2. 使用 placement new
    Foo * pfoo = new (buff) Foo;  
    
    //使用对象
    unsigned int length = pfoo->size();  
    pfoo->resize(100, 200);

    //3. 显式调用析构函数
    pfoo->~Foo();  
    
    //4. 释放预定义的缓冲
    delete [] buff;  
  }
分享到:
评论

相关推荐

    C++对象池源码示例

    1. **定义对象池结构**:首先,我们需要一个数据结构来存储池中的对象。这通常是一个动态数组或者链表,用于保存已创建但尚未被使用的对象。 2. **对象的创建与初始化**:在对象池初始化时,一次性创建所需数量的...

    C++实现高性能内存池.docx

    然而,`std::allocator`在分配内存时会立即调用对象的构造函数,这并不适用于内存池的实现,因为内存池希望先分配未构造的原始内存,然后再根据需要构造对象。因此,我们需要重写`std::allocator`的一些关键方法,如...

    高效的,固定大小的对象池

    在计算机科学和编程领域...综上所述,一个高效的固定大小对象池是通过预先分配并管理一组对象来提升性能的内存管理技术。其核心在于优化内存分配和对象复用,以减少系统开销,尤其适用于需要频繁创建和销毁对象的场景。

    对象池的一个小例子

    对象池通过预先创建一定数量的对象并存储在一个池中,当应用程序需要使用这些对象时,可以直接从池中获取而无需重新创建;当使用完毕后,再将对象归还到池中供后续使用,而不是直接销毁。 #### 三、对象池的优点 1...

    MemoryPool:使用 C++11 的简单内存池实现

    1. 首先定义一个内存块结构,包含实际数据存储区域和状态信息: ```cpp struct Block { void* data; bool is_free; }; ``` 2. 创建一个内存池类,其中包含内存块数组和管理逻辑: ```cpp class MemoryPool { ...

    面向对象软件构造-Delphi技术资料

    2. **继承与多态**: 继承允许一个类(子类)继承另一个类(父类)的特性,从而实现代码重用和扩展。多态性允许不同的对象对同一消息作出不同响应,增强了程序的灵活性。在Delphi中,继承通过`继承`关键字实现,而多...

    C#自定义对象池

    在C#中实现自定义对象池,首先需要定义一个类来存储和管理这些对象。这个类通常包含一个队列或字典来保存对象,以及一些方法如获取对象、归还对象等。以下是一个简单的对象池实现框架: ```csharp public class ...

    内存池(MemPool)

    - mempool.h:内存池的头文件,定义了内存池类和相关的接口,如alloc()用于分配内存,free()用于释放内存,以及可能的构造函数和析构函数用于初始化和清理内存池。 - mempool.cpp:内存池的实现文件,包含内存池类的...

    VMPool[2011-07-17_1_分页式虚拟内存管理,内存池].rar

    2. 内存池构造:定义一个内存池类,包含内存块的分配、回收、查找等方法,以实现动态分配和管理内存块。 3. 错误处理:添加异常处理机制,确保在内存不足或其他错误情况下,程序能正常运行并给出错误提示。 通过...

    用c++实现的内存池源码

    内存池是一种优化内存分配效率的技术,它通过预先一次性分配一大块连续内存,然后根据需要从中划分出小块内存供程序使用。这种方式可以避免频繁的小内存分配和释放带来的系统开销,尤其是在频繁创建和销毁小对象时,...

    Delphi面向对象编程思想

    Delphi的对象模型建立在VCL(Visual Component Library)框架上,这是一个丰富的组件库,包含大量预先构建的、可用于快速开发的可视化和非可视化对象。开发者可以通过拖放组件到表单(Form)上,并通过属性编辑器...

    对象缓存池AS3实现

    1. 初始化:在`ObjectPool`的构造函数中,预先创建一定数量的对象实例,并将它们存储在一个数组或者链表中。 2. 获取对象:当需要对象时,`getObject()`方法会检查池中是否有可用的对象。如果有,就从池中取出并返回...

    基于C++的内存池的实现

    为了方便管理和使用内存单元,通常会定义一个结构体来记录每个内存单元的状态,例如: ```cpp typedef struct MemoryUnit { unsigned char* Data; // 对应的物理内存地址 int DataSize; // 可管理的内存大小 int...

    EnumTest--构造顺序:父类、类成员变量、子类.zip

    当一个对象不再被引用时,垃圾收集器会回收其内存。对于枚举实例,由于它们是全局的、单例的,所以通常不会被垃圾回收,因此在这个场景下讨论析构顺序并不常见。但如果是类实例的成员变量,其析构顺序会是子类的清理...

    内存管理内存管理内存管理

    不过,即使是在这样一个简单的计算机中,您也会有问题,尤其是当您不知道程序的每个部分将需要多少内存时。如果您的空间有限,而内存需求是变化的,那么您需要一些方法来满足这些需求: 确定您是否有足够的内存...

    内存池管理

    在6.2.1节中给出的`MemoryPool`类就是一个典型的内存池实现方式。该类定义了几个关键成员变量:`pBlock`用于指向内存块链表的头部;`nUnitSize`表示每个单元的大小;`nInitSize`表示初始化时分配的单元数量;`...

    Cpp面经200问.pdf

    ### C++面经知识点详解 ...构造函数用于创建对象,拷贝构造函数用于创建一个新对象作为现有对象的副本,赋值操作符用于将一个对象的内容复制给另一个已存在的对象。 #### 83. 拷贝构造函数与赋值...

    C++高级参考手册,讲解C++ 语法,函数重载,构造函数等

    3. **隐藏实现**:隐藏实现是数据抽象的一部分,确保用户只能通过预先定义的公共接口与对象交互,而不能直接访问内部数据,这有助于防止错误的修改和提高代码的稳定性和安全性。 4. **初始化与清除**:在C++中,...

    JAVA程序设计教学课件完美版资料.ppt

    在Java中,你可以通过`class`关键字定义一个类,并使用`new`关键字创建该类的对象。 2. **构造方法**:构造方法是一个特殊的方法,用于初始化新创建的对象。当创建类的新实例时,会自动调用构造方法。构造方法的...

    java面向对象程序设计PPT课件.ppt

    Java的垃圾收集机制(Garbage Collection)自动管理内存,当一个对象不再被引用时,垃圾收集器会回收其占用的内存空间。 `static`关键字用于声明静态变量和方法,它们属于类而不是类的实例。静态变量是所有实例共享...

Global site tag (gtag.js) - Google Analytics