Do custom allocator apply just to containers, and how do i apply them to any memory allocation

Apr 26, 2021 at 10:04pm
https://en.cppreference.com/w/cpp/named_req/Allocator

I am referring to this ^^^^ kinds of custom of memory allocator (if there is a different kind of allocator let me know)

I am asking because I have a certain allocation and deallocation pattern where I do lot of allocations and then free them all at once (this pattern repeats many times),
and I am looking for a way to optimize away the alloc and free cost, and I am looking for what is the "proper" way to write that out

One possible solution (which I am leaning towards) is simply making a std::vector (which stores the objects)
and pushing in all the "new" objects and when I am done simply clearing the vector (aka marking the memory as unused)
The bigest downside from what i can tell using this method (which does not apply to my case) is that if you have objects of different sizes you can not use the same vector

A second solution would be to use a linear allocator from (https://github.com/mtrebi/memory-allocators) which acts similarly to the std::vector example as shown above

A third option (which is probably not a valid option because I misunderstand what an allocator is) is using a STL complaint allocator every time I am calling new

Here is a snippet of code to better understand my problem:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main() {
	for ( 1000+ times){
		...
		for (many iter){
			...
			new some_object
			...//compute heavy stuff
		}
		... //other compute heavy stuff
		for (many iter){
			delete some_object
		}
	}
}

Lines 6 and 11 take up a large portion of total execution time



P.S. there is probably a better title for this question, if you have one let me know
Last edited on Apr 26, 2021 at 10:52pm
Apr 27, 2021 at 12:25am
If you need many objects of different types then you're not going to be able to optimize much. This is about the best you can hope for:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
size_t size = estimate_memory_requirements();
std::unique_ptr<char[]> mem(new char[size]);
char *next = mem.get();
for (auto &i : objects_to_allocate){
    auto p = next;
    i.pointer = p;
    next += i.size;
    i.constructor(); //calls placement new on pointer
    //compute heavy stuff
}

//other compute heavy stuff

//you can comment out this loop ONLY if destructors are trivial
for (auto &i : objects_to_allocate)
    i.destructor(); //calls destructor on pointer (NOT delete)

mem.reset();
Apr 27, 2021 at 10:09am
How many different sized objects are we talking about here? If a few, then perhaps a memory pool for each object size?
Apr 27, 2021 at 11:57am
Is it always the same objects, or does the mix of objects change between iterations?

If it is always the same set of objects, you could just create them once and then re-initialize them before each iteration. Tear them down just once at the end.

Apr 27, 2021 at 4:26pm
Another poster, @mitsuru, apparently had good luck applying some of the discussion in this thread:
https://www.cplusplus.com/forum/general/273999/
Apr 27, 2021 at 4:27pm
for my case i only have 1 object type (so same size always)
but i am asking incase there is a built in langauge construct to allow me to do that without resorting to manually writing the code my self


Edit i just found this out:
1
2
3
4
5
6
7
8
9
int main() {
	std::vector<int> v(10);
	alignas(int) std::byte buf[sizeof(int)];

	int* i = new(buf) int; //alocate starting at the address of  buf
	int* j = new(&v[0]) int; //alocate starting at the address of  buf
	assert((size_t)i == (size_t)buf);
	assert((size_t)j == (size_t)&v[0]);
}

which allows you to allocate in place
this is called new's placement parameters, more on: https://en.cppreference.com/w/cpp/language/new section 2.1.1
Last edited on Apr 27, 2021 at 5:07pm
Apr 27, 2021 at 4:59pm
There's no point in aligning the vector.
Topic archived. No new replies allowed.