Как аллоцировать неизменяемые поля класса, использующие динамическую аллокацию вместе с самим классом используя 1 вызов аллокатора

Есть класс

class A
{
public:
...
private:
    std::string field1;
    std::string field2;
};

Этот класс всегда аллоцируется на куче, его поля после создания никак не именяются. Как сделать так, чтоб класс и поля выделились за одну аллокацию. Думаю эта проблема решается с помощью передачи пользовательского аллокатора, возможно есть готовая реализация?


Ответы (1 шт):

Автор решения: ByteGear

Вообще тут зависит от контекста использования, если все строки хранятся в bss области (всегда и полностью заданы через двойные кавычки "" и не строятся в программе), можно в классе хранить std::string_view - аллокаций вообще не будет:

class A
{
public:
    A(const char* a, const char* b) : field1(a), field2(b) {}
...
private:
    std::string_view field1;
    std::string_view field2;
};

// ...

A a("Строка 1", "Строка 2");

Если по каким-то причинам нужно хранить в одном месте обе строки в принципе можно заменить std::string на const char[size], а size передавать через шаблонный параметр.

Что-то вроде этого:

template<size_t size_1, size_t size_2>
class A
{
public:
...
private:
    const char field1[size_1 + 1]; // +1 на символ null
    const char field2[size_1 + 1];
};

В таком случае все поля будут располагать в одном месте единым блоком памяти, а взаимодействовать со строками так же можно через std::string_view.

Ключевой недостаток: требуется чтобы размеры строк были известны на этапе компиляции программы.

Если размеры не известны на стадии компиляции можно сделать как-то так:

class A
{
public:
    A(std::string a, std::string b)
        : field1(new char(a.size() + b.size() + 2)),
          field2(field1 + a.size() + 1) {
        std::memmove(field1, a.data(), a.size() + 1);
        std::memmove(field2, b.data(), b.size() + 1);
    }
    ~A() { if(field1) delete field1; }
...
private:
    const char* field1 = nullptr;
    const char* field2;
};

Объект с двумя указателями оставляем на стэке, блок памяти с двумя строками разделённые null-символом выделяется в куче одной аллокацией.

→ Ссылка