Как аллоцировать неизменяемые поля класса, использующие динамическую аллокацию вместе с самим классом используя 1 вызов аллокатора
Есть класс
class A
{
public:
...
private:
std::string field1;
std::string field2;
};
Этот класс всегда аллоцируется на куче, его поля после создания никак не именяются. Как сделать так, чтоб класс и поля выделились за одну аллокацию. Думаю эта проблема решается с помощью передачи пользовательского аллокатора, возможно есть готовая реализация?
Ответы (1 шт):
Вообще тут зависит от контекста использования, если все строки хранятся в 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-символом выделяется в куче одной аллокацией.