Заставьте 2 нестатических поля (которые являются динамическими массивами) использовать память рядом друг с другом

Позволять B1 а также B2 быть классами хранения динамического размера.
(например B1~std::vector<char>B2~std::vector<float>)

В C++11, если я кодирую B1 а также B2 "s move а также copy функция (правило пяти), класс C который содержит их как поля, будет автоматически копироваться / перемещаться по умолчанию.

class C{
    B1 b1; B2 b2;
};

Это работает очень хорошо.

проблема

Сегодня я получил результат профиля + провёл тест на производительность.
Основная цель: я должен сделать b1 а также b2 того же экземпляра C выделить память рядом друг с другом:-

b1[0]  b1[1] ... b1[b1.size-1] (minimum gap) b2[0]  b2[1] ... b2[b2.size-1] 

Если я смогу, я получу повышение производительности на 10-20% для всей программы.

Мое плохое решение

Я могу использовать пользовательский распределитель, как это (псевдокод):

class C{
    B1 b1; 
    B2 b2;
    Allocator* allo_; // can be heap allocator 
    public: void reserve(int size){
        //old : b1.reserve(size); b2.reserve(size);  .... so easy
        //new :-
        B1 b1Next; B2 b2Next;
        int nb1=b1Next.howMuchIWant(size); 
        int nb2=b2Next.howMuchIWant(size);
        //^ request amount of bytes needed if capacity="size"
        void* vPtr=allo_->allocate(nb1+nb2);
        b1Next.setMemory(vPtr);
        b2Next.setMemory(vPtr + nb1);  //add "vPtr" by "nb1" bytes
        b1Next=b1;   //copy assignment (not move memory)
        b2Next=b2;   //copy assignment (not move memory)
        b1=std::move(b1Next);   //move memory
        b2=std::move(b2Next);   //move memory 
        //clean up previous "vPtr" (not shown)
    }
};

Это работает, но код становится намного сложнее отлаживать / поддерживать. Не говоря уже о C Перемещаем и копируем.

В старой версии все copy / move беспорядок появляются только в B1 а также B2,
Теперь, беспорядок появляется в каждом классе, который использует структуру данных, как B1 а также B2 непосредственно.

Вопрос

Какая техника C++ / дизайн-паттерн / идиома может помочь?
Чтобы ответить, никакого исполняемого кода не требуется. Псевдокод или просто концепция достаточно.

Я так сожалею, что не предоставил MCVE.
Пользовательский распределитель и управление массивами - вещи, которые действительно трудно минимизировать.

1 ответ

Одна возможность улучшить локальность данных исходит от struct из vectorс vector из structs. Вместо

struct S
{
    std::vector<char> c;
    std::vector<int> i;
};
S data;

использовать

struct S
{
    char c;
    int i;
};
std::vector<S> data;

Таким образом, данные всегда хранятся вместе, и вам не нужно возиться с пользовательскими распределителями. Применимо ли это в вашей ситуации, прежде всего, зависит от двух условий:

  • Нужно ли иметь все char (или же int) смежный? Например, потому что API вызывается регулярно, что требует vector соответствующего типа.
  • Количество сохраненных char а также int равно (хотя бы почти равно)?
Другие вопросы по тегам