MSVC++ 对象内存模型深入解析与具体应用
前言:本文之所以强调MSVC, 旨在提醒读者在不同平台和解释器下内存布局和实现上存在差异,但编程思想通用,文中内容大多来自笔者实际工作经验和网上搜集,力求正确,但水平有限,如有不当之处,敬请指出
面向对象:本文面向有一定C/C++基础,并且可以读懂部分汇编的读者
版权:欢迎转载,但请注明出处http://www.cppblog.com/dawnbreak/, 保留对本文的一切权力
目录
1. C++基本类型与结构体内存布局
Key words: class, struct, memory alignment
2.虚表, 多态与动态绑定
Key words: Virtual Table, polymiorphism
3.对象池
Key words: object pool , reload, new ,delete
4.内存泄漏检测
Key words: memory leak detect
5.智能指针
Key words: smart pointer
6. 编译期类型约束
Key words: compile-time ,type-constraint
第三章 对象池
Key words: object pool
对象池
对象池是一种避免在整个程序生存周期内重复创建或删除大量对象的方法。在代码里无论何时当你需要一个对象时,你可以在对象池中申请一个。当你使用完毕后,将其归还到池中。对象池仅仅创建一次对象,所以他们的构造函数仅仅被调用一次,并不是每次使用时都调用。所以在对象池创建时仅仅做一些通用的初始化,而在对象实例调用其他非构造函数时进行特别赋值及操作。
一个对象池的实现
1
#include <queue>
2
#include <vector>
3
#include <stdexcept>
4
#include <memory>
5
using std::queue;
6
using std::vector;
7
//
8
// template class ObjectPool
9
//
10
// Provides an object pool that can be used with any class that provides a
11
// default constructor
12
//
13
// The object pool constructor creates a pool of objects, which it hands out
14
// to clients when requested via the acquireObject() method. When a client is
15
// finished with the object it calls releaseObject() to put the object back
16
// into the object pool.
17
//
18
// The constructor and destructor on each object in the pool will be called only
19
// once each for the lifetime of the program, not once per acquisition and release.
20
//
21
// The primary use of an object pool is to avoid creating and deleting objects
22
// repeatedly. The object pool is most suited to applications that use large
23
// numbers of objects for short periods of time.
24
//
25
// For efficiency, the object pool doesn’t perform sanity checks.
26
// It expects the user to release every acquired object exactly once.
27
// It expects the user to avoid using any objects that he or she has released.
28
//
29
// It expects the user not to delete the object pool until every object
30
// that was acquired has been released. Deleting the object pool invalidates
31
// any objects that the user has acquired, even if they have not yet been released.
32
//
33
template <typename T>
34
class ObjectPool
35

{
36
public:
37
//
38
// Creates an object pool with chunkSize objects.
39
// Whenever the object pool runs out of objects, chunkSize
40
// more objects will be added to the pool. The pool only grows:
41
// objects are never removed from the pool (freed), until
42
// the pool is destroyed.
43
//
44
// Throws invalid_argument if chunkSize is <= 0
45
//
46
ObjectPool(int chunkSize = kDefaultChunkSize)
47
throw(std::invalid_argument, std::bad_alloc);
48
//
49
// Frees all the allocated objects. Invalidates any objects that have
50
// been acquired for use
51
//
52
~ObjectPool();
53
//
54
// Reserve an object for use. The reference to the object is invalidated
55
// if the object pool itself is freed.
56
//
57
// Clients must not free the object!
58
//
59
T& acquireObject();
60
//
61
// Return the object to the pool. Clients must not use the object after
62
// it has been returned to the pool.
63
//
64
void releaseObject(T& obj);
65
protected:
66
//
67
// mFreeList stores the objects that are not currently in use
68
// by clients.
69
//
70
queue<T*> mFreeList;
71
//
72
// mAllObjects stores pointers to all the objects, in use
73
// or not. This vector is needed in order to ensure that all
74
// objects are freed properly in the destructor.
75
//
76
vector<T*> mAllObjects;
77
int mChunkSize;
78
static const int kDefaultChunkSize = 10;
79
//
80
// Allocates mChunkSize new objects and adds them
81
// to the mFreeList
82
//
83
void allocateChunk();
84
static void arrayDeleteObject(T* obj);
85
private:
86
// Prevent assignment and pass-by-value.
87
ObjectPool(const ObjectPool<T>& src);
88
ObjectPool<T>& operator=(const ObjectPool<T>& rhs);
89
};
template <typename T>
ObjectPool<T>::ObjectPool(int chunkSize) throw(std::invalid_argument,
std::bad_alloc) : mChunkSize(chunkSize)


{

if (mChunkSize <= 0)
{
throw std::invalid_argument(“chunk size must be positive”);
}
// Create mChunkSize objects to start.
allocateChunk();
}
//
// Allocates an array of mChunkSize objects because that’s
// more efficient than allocating each of them individually.
// Stores a pointer to the first element of the array in the mAllObjects
// vector. Adds a pointer to each new object to the mFreeList.
//
template <typename T>
void ObjectPool<T>::allocateChunk()


{
T* newObjects = new T[mChunkSize];
mAllObjects.push_back(newObjects);

for (int i = 0; i < mChunkSize; i++)
{
mFreeList.push(&newObjects[i]);
}
}
//
// Freeing function for use in the for_each algorithm in the
// destructor
//
template<typename T>
void ObjectPool<T>::arrayDeleteObject(T* obj)


{
delete [] obj;
}
template <typename T>
ObjectPool<T>::~ObjectPool()


{
// Free each of the allocation chunks.
for_each(mAllObjects.begin(), mAllObjects.end(), arrayDeleteObject);
}
template <typename T>
T& ObjectPool<T>::acquireObject()


{

if (mFreeList.empty())
{
allocateChunk();
}
T* obj = mFreeList.front();
mFreeList.pop();
return (*obj);
}
template <typename T>
void ObjectPool<T>::releaseObject(T& obj)


{
mFreeList.push(&obj);
}
以上是对象池的一个简单实现,使用队列mFreeList记录可以使用的对象,使用向量mAllObjects来记录所有的对象,以便安全释放内存
在实际使用中,可以使用栈来保存可用对象,这样可以更加高效的使用内存