2
\$\begingroup\$

Here is a thirdfollow up on Reusable storage for array of objects, Reusable storage for array of objects V2 and Reusable storage for array of objects V3, taking into account the provided answers.
The following code should be compliant at least with gcc, clang, msvc and for C++14 and beyond.
In this version, I leave only the core code for lisibility and provide a testbench on Compiler Explorer.

#include <cstddef>
#include <cstdint>
// @ adding forgotten cstdlib
#include <cstdlib>
#include <limits>
#include <new>
#include <type_traits>
// type-punning reusable buffer
// holds a non-typed buffer (actually a char*) that can be used to store any
// types, according to user needs
class Buffer {
 private:
 // destructing functor storage
 // required to call the correct object destructors
 void (*Destructors)(Buffer*) noexcept = nullptr;
 // storage address
 unsigned char* Storage = nullptr;
 // objects address
 unsigned char* Objects = nullptr;
 // number of stored elements
 std::size_t CountOfStoredObjects = 0;
 // buffer size in bytes
 std::size_t StorageSizeInBytes = 0;
 // computes the smallest positive offset in bytes that must be applied to
 // Storage in order to have alignment a Alignment is supposed to be a valid
 // alignment
 static std::size_t OffsetForAlignment(unsigned char const* const Ptr,
 std::size_t Alignment) noexcept {
 std::size_t Res = static_cast<std::size_t>(
 reinterpret_cast<std::uintptr_t>(Ptr) % Alignment);
 if (Res) {
 return Alignment - Res;
 } else {
 return 0;
 }
 }
 public:
 // allocates a char buffer large enough for Counts object of type T and
 // default-construct them
 template <typename T>
 T* DefaultAllocate(const std::size_t Count) {
 if (Count > (std::numeric_limits<std::size_t>::max() - alignof(T)) /
 sizeof(T)) {
 throw std::bad_alloc();
 }
 // Destroy previously stored objects
 if (Destructors) {
 Destructors(this);
 }
 std::size_t RequiredSize = sizeof(T) * Count + alignof(T);
 if (StorageSizeInBytes < RequiredSize) {
 // Creating a storage of RequiredSize bytes
 unsigned char* NewStorage = reinterpret_cast<unsigned char*>(
 std::realloc(Storage, RequiredSize));
 if (NewStorage == nullptr) {
 throw std::bad_alloc();
 }
 Storage = NewStorage;
 StorageSizeInBytes = RequiredSize;
 }
 unsigned char* AlignedStorage =
 Storage + OffsetForAlignment(Storage, alignof(T));
 // initializing an dynamic array of T on the storage
 T* Tmp = ::new (AlignedStorage) T[Count];
 Objects = reinterpret_cast<unsigned char*>(Tmp);
 // update nb of objects
 CountOfStoredObjects = Count;
 // create destructors functor
 Destructors = [](Buffer* PBuffer) noexcept {
 PBuffer->Destructors = nullptr;
 T* ToDestruct = reinterpret_cast<T*>(PBuffer->Objects);
 // Delete elements in reverse order of creation
 while (PBuffer->CountOfStoredObjects > 0) {
 --(PBuffer->CountOfStoredObjects);
 ToDestruct[(PBuffer->CountOfStoredObjects)].~T();
 }
 ::operator delete[](ToDestruct, ToDestruct);
 PBuffer->CountOfStoredObjects = 0;
 PBuffer->Objects = nullptr;
 };
 return Tmp;
 }
 ~Buffer() noexcept {
 // Ending objects lifetime
 if (Destructors) {
 Destructors(this);
 }
 // Releasing storage
 std::free(Storage);
 }
};

[EDIT] pinpointing fixes with // @ ... and replacing ```std::function``` by a simplier function pointer

asked Sep 7, 2023 at 10:19
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Sorry if I missed some, I thought I did. Give me time to go other it again. I will post a comment when I'm done. \$\endgroup\$ Commented Sep 7, 2023 at 10:26
  • \$\begingroup\$ @G.Sliepen I'm utterly sorry, I didn't find what issue I may have forgotten (perhaps I didn't fix them correctly). I made an edit to pinpoint where I addressed the mentioned problems. Btw I also managed to remove std::function. I had an issue with msvc/C++14 that was merely due to a missing compiler option. \$\endgroup\$ Commented Sep 7, 2023 at 16:31

0

Know someone who can answer? Share a link to this question via email, Twitter, or Facebook.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.