Skip to content

Commit 4f10e65

Browse files
committed
Update README.md
1 parent 28fe1ca commit 4f10e65

File tree

1 file changed

+46
-4
lines changed

1 file changed

+46
-4
lines changed

README.md

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,54 @@ MemoryPool is mostly compliant with the C++ Standard Library allocators. This me
2626

2727
Usage
2828
-------------------------
29-
Put `MemoryPool.h` and `MemoryPool.tpp` into your project folder and include `MemoryPool.h` into your project. These files define a single template class in the common namespace:
30-
Template <typename T, size_t BlockSize = 4096>
29+
Put `MemoryPool.h` and `MemoryPool.tcc` into your project folder and include `MemoryPool.h` into your project. These files define a single template class in the common namespace:
30+
```C++
31+
template <typename T, size_t BlockSize = 4096>
32+
```
33+
3134
Here, `T` is the type of the objects you want to allocate and `BlockSize` is the size of the chunks in bytes the allocator will ask from the system. `T` can be any object, while `BlockSize` needs to be at least twice the size of `T`. After that, you create an instance of `MemoryPool` class and use it just like a standard allocator object. Here is an example:
32-
35+
```C++
36+
#include <iostream>
37+
#include "MemoryPool.h"
38+
39+
int main()
40+
{
41+
MemoryPool<size_t> pool;
42+
size_t* x = pool.allocate();
43+
44+
*x = 0xDEADBEEF;
45+
std::cout << std::hex << *x << std::endl;
46+
47+
pool.deallocate(x);
48+
return 0;
49+
}
50+
```
51+
52+
Normally, if `T` is a class that has a non-default constructor, you need to call `MemoryPool.construct(pointer)` on the returned pointer before use and `MemoryPool.destroy(pointer)` after. Apart from the standard allocator functions, MemoryPool defines two new functions: `newElement(Args...)` and `deleteElement(pointer)`. These functions behave just like the standard `new` and `delete` functions and eliminate the need to call constructors and destructors separately. The only difference is that they can only allocate space for a type `T` object. We can rewrite the code above using these functions (we did not use them since `size_t` does not need to be constructed):
53+
```C++
54+
#include <iostream>
55+
#include "MemoryPool.h"
56+
57+
int main()
58+
{
59+
MemoryPool<size_t> pool;
60+
size_t* x = pool.newElement();
61+
62+
*x = 0xDEADBEEF;
63+
std::cout << std::hex << *x << std::endl;
64+
65+
pool.deleteElement(x);
66+
return 0;
67+
}
68+
```
69+
70+
The `Args` in `newElement` is whatever you would pass to the constructor of `T` (magic of C++11 perfect forwarding).
71+
72+
For more information, see the reference to [allocator_traits] (http://www.cplusplus.com/reference/memory/allocator_traits/) or the [standard allocator] (http://www.cplusplus.com/reference/memory/allocator/).
73+
74+
More examples are provided with the code.
3375

34-
How to Pick BlockSize
76+
Picking BlockSize
3577
-------------------------
3678
`BlockSize` is the size of the chunks in bytes the allocator will ask from the system. Picking the correct `BlockSize` (the second, optional, template parameter) is essential for good performance. I suggest you pick a power of two, which may decrease memory fragmentation depending on your system. Also, make sure that `BlockSize` is at least several hundred times larger than the size of `T` for maximum performance. The idea is, the greater the `BlockSize`, the less calls to `malloc` the library will make. However, picking a size too big might increase memory usage unnecessarily and actually decrease the performance because `malloc` may need to make many system calls. For objects that contain several pointers, the default size of 4096 bytes should be good. If you need bigger object, you may need to time your code with larger sizes for `BlockSize`.
3779

0 commit comments

Comments
 (0)