Hacker News new | ask | show | jobs
by markisus 877 days ago
I usually like to place all dynamically heap objects of type T into an std::vector<T>, if possible. There is sometimes an obvious point where the entire batch should be discarded and a new batch should be built. At this point, you can call vector.clear() which avoids deallocation/allocation cost for the new batch, as long as it is not bigger than the old batch. This is a sort of quick and dirty arena allocation.

This style is also more cache friendly if you are going to be looping through the elements.

2 comments

I do this too, when I can either use a handle/index instead of a pointer, or when I can guarantee that the vectors size is constant (so that pointers/iterators are stable). I’ve also written my own vector that stores its elements in pages so that if its capacity needs to increase, the elements don’t need relocation.

I only really use C++ for a toy game engine right now and in that codebase I don’t use any smart pointers and most objects/functions get passed references to their object dependencies. I classify objects into groups where each groups ownership is very clear. So its owner is responsible for maintaining the memory and any raw pointers can always be assumed to be borrowed references. I use handles then the underlying objects lifetime might differ from whatever is holding a handle to it. Short lived objects are kept trivial and allocated from stack/bump allocators or pools and reset at well defined times (every frame, end of level, etc)

I’m much happier this way than when I used smart pointers or when I had less well defined memory ownership.

Interesting - is there a type safe way to do this? vector<variant<>>? and/or a custom “vector allocator” to hide the details?
In my example, the T is one specific type. So you could have std::vector<Cat>. If you also have Dogs, you just make another vector std::vector<Dog>. It works fine with the standard allocator. You don't have to do anything special.
Ah okay that makes sense to me
You can do a Vector<TaggedUnion<Union>>. https://pagghiu.github.io/SaneCppLibraries/library_foundatio...

I have not been working (yet) on custom allocators, but that's on the roadmap: https://pagghiu.github.io/SaneCppLibraries/library_container...

If you wanted a factory that allocated vectors of a variety of known types, you'd probably declare template <typename T> before the generator function, so that on compilation a separate version of that function would be emitted for each type you passed to it.

(Not really a c++ expert, but that's my understanding; someone more knowledgeable can correct me).

Why would you need a variant? If you have one of something, put it on the stack. If you have a lot of the a type, put them in a vector.
Isn't that an arena allocator at that point?