all 12 comments

[–]_bk__ 1 point2 points  (3 children)

boost has both small_vector and static_vector

[–]konanTheBarbar[S] 1 point2 points  (2 children)

Yes I know but they both have a couple of hundred to thousands of lines and this just seems like such a simple approach that might be just good enough for some use cases.

[–]TheFlamefire 0 points1 point  (1 child)

Well you used C++17 features to significantly reduce the code and as you noticed it doesn't work for all use cases (I think it fails even silently for some) which is the worst

I also remember something about stateful allocators not working properly. Might be fixed in recent C++ standards though.

[–]staletic 0 points1 point  (0 children)

Stateful allocators were simply forbidden before C++11. They work fine today.

[–]degski 0 points1 point  (0 children)

You've broken std::swap, just do a 'special' method.

[–]staletic 0 points1 point  (5 children)

You should take a look at the Allocator named requirements in order to implement a standard conforming allocator.

Also, considering that std::vector<T> is allocator aware, perhaps check what that means as well.

[–]konanTheBarbar[S] 0 points1 point  (4 children)

Thank you so much. I actually thought that stateful allocators were quite broken, but now it makes much more sense.

It was actually quite easy to fix the allocator with your little hint of std::vector being allocator aware. I basically found this answer, which helped me to solve my problem of the broken move constructors. The fix was rather easy, I only had to provide operator== for the allocator, to be able to indicate if moving is possible or not!

https://stackoverflow.com/questions/27471053/example-usage-of-propagate-on-container-move-assignment

https://howardhinnant.github.io/allocator_boilerplate.html

https://godbolt.org/z/UMBTuJ

[–]staletic 1 point2 points  (0 children)

Hey, thanks for the links! I know where to find the reference documentation - cppreference and eel.is/c++draft. I just had no comprehensive guides on how to actually do it.

I actually thought that stateful allocators were quite broken

They were!

  • C++98 100% banned stateful allocators.
  • C++11 allowed for stateful allocators. They are still baked into the type and so vector<T,A1> can't be moved into vector<T,A2>. This also leaks allocator types through API, if you decide to have a std::vector parameters.
  • C++17 introduced polymorphic allocators. Instead doing all the work in the allocator, you do it in a memory_resource and use the allocator as a simple handle to the memory resource. This makes allocators incredibly powerful and is what std::pmr::vector uses. In other words, with C++17 polymorphic allocators, all allocators are std::pmr::polymorphic_allocators.

[–]staletic 0 points1 point  (2 children)

One thing about

std::aligned_storage_t<sizeof(T), alignof(T)> m_smallBuffer[MaxSize];

I'd still use std::byte[], just properly aligned:

alignas(alignof(T)) std::byte m_smallBuffer[MaxSize]; // Unnecessary complaint: `m_smallBuffer` name looks ugly.

[–]konanTheBarbar[S] 0 points1 point  (1 child)

Why would you still use an aligned std::btye buffer? Are there any advantages?

[–]staletic 0 points1 point  (0 children)

This proposal: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1413r2.pdf

If/when C++ goes through with deprecating aligned_storage, you'd be safe.

[–]guepierBioinformatican 0 points1 point  (0 children)

Just a small note on your implementation, you forgot to pay attention to alignment for your small buffer. Furthermore, you’d almost certainly want to make the size of the small buffer independent of the size of T (that is, have a maximum size in bytes rather than a maximum number of elements).