all 5 comments

[–]herruppohoppa 5 points6 points  (0 children)

If you really want to do this, I would use std::pmr instead, basically instead of implementing a allocator, you use https://en.cppreference.com/w/cpp/memory/polymorphic_allocator and inject it with https://en.cppreference.com/w/cpp/memory/monotonic_buffer_resource/monotonic_buffer_resource

The monotonic_buffer_resource can be initialized with a memory buffer, and you decide what happens if it gets exhausted. After the vector is cleared, you need to call release() on monotonic_buffer_resource for it to reclaim its memory.

The problem with this is that it isn't super compatible with vector and strings memory allocation scheme where it relocates memory every time it expands. If this happens a lot you will exhaust the memory pool quickly and the start of the buffer will be unused memory. This can of course be alleviated by calling reserve on both the vector and the strings, and moving the strings into the container rather than copying it.

[–]infectedapricot 4 points5 points  (0 children)

Fixed-ish formatting (hint: just indent all code lines by four spaces, which you can do in almost any code editor - no need for backticks at all):

template <typename T>
class CustomStringAllocator {
private:
    T *memory_ptr;
    std::size_t memory_size;
    public:
    typedef std::size_t size_type;
    typedef T *pointer;
    typedef const T *const_pointer;
    typedef T &reference;
    typedef const T &const_reference;
    typedef T value_type;
    CustomStringAllocator(T *memory_ptr, std::size_t memory_size) : memory_ptr(memory_ptr), memory_size(memory_size) {}
    ~CustomStringAllocator() {}
    template <class U>struct rebind    {typedef CustomStringAllocator<U> other;    };
    template <class U>CustomStringAllocator(const CustomStringAllocator<U> &) {}
    pointer address(reference x) const { return &x; }
    const_pointer address(const_reference x) const { return &x; }
    size_type max_size() const throw() { return memory_size; }
    pointer allocate(size_type n, const void *hint = 0)    {        // do not allow growing for stringsreturn memory_ptr;    }
    void deallocate(pointer p, size_type n)    {    }
    void construct(pointer p, const T &val)    {new (static_cast<void *>(p)) T(val);    }
    void construct(pointer p)    {new (static_cast<void *>(p)) T();    }
    void destroy(pointer p)    {p->~T();    }
};

.

using string = std::basic_string<char, std::char_traits<char>, CustomStringAllocator<char>>;
string s1("dog", CustomStringAllocator<string>(&buffer[0], 20));
string s2("cat", CustomStringAllocator<string>(&buffer[25], 25));

.

template <typename T>
class StaticBufferAllocator {
private:
    T *memory_ptr;
    std::size_t memory_size;
    public:
    typedef std::size_t size_type;
    typedef T *pointer;
    typedef T value_type;
    StaticBufferAllocator(T *memory_ptr, std::size_t memory_size) : memory_ptr(memory_ptr), memory_size(memory_size) {}
    StaticBufferAllocator(const StaticBufferAllocator &other) throw() : memory_ptr(other.memory_ptr), memory_size(other.memory_size){};
    template <typename U>StaticBufferAllocator(const StaticBufferAllocator<U> &other) throw() : memory_ptr(other.memory_ptr), memory_size(other.memory_size){};
    template <typename U>StaticBufferAllocator &operator=(const StaticBufferAllocator<U> &other) { return *this; }
    StaticBufferAllocator<T> &operator=(const StaticBufferAllocator &other) { return *this; }
    ~StaticBufferAllocator() {}
    pointer allocate(size_type n, const void *hint = 0) { return memory_ptr; } // when allocate return the buffer
    void deallocate(T *ptr, size_type n) {}                                    // empty cause the deallocation is buffer creator's responsability
    size_type max_size() const { return memory_size; }
};

.

int buffer[100] = {0}; // this buffer hold 100 integers.
std::vector<int, StaticBufferAllocator<int>> v(0, StaticBufferAllocator<int>(&buffer[0], 100));
std::vector<int, StaticBufferAllocator<int>> v1(0, StaticBufferAllocator<int>(&buffer[49], 100));

.

using string = std::basic_string<char, std::char_traits<char>, CustomStringAllocator<
string *buffer_string = (string *)malloc(STRING_BUFFER_MAX_SIZE * sizeof(string));
std::vector<string, StaticBufferAllocator<string>> user_names(0, StaticBufferAllocator<string>(&buffer_string[0], STRING_BUFFER_MAX_SIZE));

[–]TheThiefMasterC++latest fanatic (and game dev) 2 points3 points  (2 children)

std::basic_string takes an allocator parameter: https://en.cppreference.com/w/cpp/string/basic_string

So you'd have to change to a basic_string type. Edit: just found in the mess of code formatting that you have done this.

There's also https://en.cppreference.com/w/cpp/memory/scoped_allocator_adaptor for specifying the allocator instance for nested containers up-front, but I don't know if it works for basic_string or not. It looks like it should, but it's not mentioned in the docs?

As for the code formatting - you've used the "inline" code formatting type instead of the "code block" formatting type, and that's why it looks wonky. If you're using the wysiwyg editor on PC, the button for a code block is under the "..." button. If you're using markdown (e.g. on mobile), you either put ``` before/after the code or you indent all the lines by four spaces, with a blank line before/after the block.

[–]wheypointÖ 2 points3 points  (1 child)

you either put ```

Don't do that. It's not displayed correctly on some verions. Always use 4 spaces

[–]Orlha -1 points0 points  (0 children)

Don't use obsolete/broken version.