Массив выровненной структуры, которая индуцирует регулярный массив отдельных членов - PullRequest
0 голосов
/ 01 июля 2019

Если у меня есть структура (например, employee ниже), массив такой структуры индуцирует пошаговые массивы всех членов структуры, только если размер структуры является (наименьшим) общим кратным (LCM) Размер всех членов.

В противном случае в массиве будут указатели на конкретные экземпляры элементов, у которых не будет целых расстояний указателей (измеренных в размере класса элемента).

Так, например, с учетом этой структуры:

struct employee{
    std::string name;
    short salary;
    std::size_t age;
};

A std::vector<employee> v (или массив employee[N] в этом отношении) индуцирует расширенный массив salary членов (с шагом sizeof(employee)/sizeof(short)), а также расширенные массивы age.

То есть, массив зарплат выбирается случайным образом &(v.data()->salary) + sizeof(employee)/sizeof(short)* n.

Однако это не вызывает большого количества имен, потому что sizeof(employee) (= 48) не кратно sizeof(std::string) (32) (в моей системе).

Конечно, я мог бы определить структуру другим способом, чтобы разрешить это:

struct alignas(32) employee{ // or alignas(sizeof(std::string))
    std::string name;
    short salary;
    std::size_t age;
    employee(short salary, std::size_t age) : salary{salary}, age{age}{}
};

Мне интересно, единственный ли способ добиться этого - найти этот правильный аргумент alignas. Кроме того, если есть автоматический способ получить это число без необходимости вручную находить общий множитель.

Мне кажется, что самый общий способ сделать это, не задумываясь, это сделать что-то вроде:

struct alignas(LCM(sizeof(std::string), sizeof(short), sizeof(std::size_t) ) employee{
    std::string name;
    short salary;
    std::size_t age;
    employee(short salary, std::size_t age) : salary{salary}, age{age}{}
};

То есть я должен заранее перечислить всех членов. Я мог бы использовать constexpr std::lcm, связав его несколько раз).

Это правильный способ сделать это?

Кроме того, всегда можно найти патологические случаи, в которых это даже не работает, потому что есть дополнительные ограничения, что выравнивание должно быть степенью 2 (в некоторых системах). В этом случае общее кратное число также должно быть степенью 2 и может быть огромным:

using password_type = std::array<char, 103>; // suppose I cannot change the 103

struct alignas(std::lcm(std::lcm(std::lcm(sizeof(std::string), sizeof(short)), sizeof(std::size_t)), sizeof(password_type))) employee{ // bad alignment
    password_type password;
    std::string name;
    short salary;
    std::size_t age;
    employee(short salary, std::size_t age) : salary{salary}, age{age}{}
};

...error: requested alignment ‘3296’ is not a positive power of 2

Для выравнивания LCM необходимо вручную изменить выравнивание конкретного элемента или добавить потолок constexpr до ближайшей степени 2.

struct alignas(std::lcm(std::lcm(std::lcm(sizeof(std::string), sizeof(short)), sizeof(std::size_t)), 128)) employee{ // bad alignment
    alignas(128) password_type password;
    std::string name;
    short salary;
    std::size_t age;
    employee(short salary, std::size_t age) : salary{salary}, age{age}{}
};

Однако это все еще не решает проблему, потому что alignas не является частью password_type, кажется, что единственное решение - это иметь версию std::array, которая также принимает внутренний аргумент выравнивания! std::aligned_array<char, 103, 128>.

Хорошо, я все еще мог сделать это, но за счет изменения других классов, которые изначально не были связаны с employee.

struct alignas(128) password_type : std::array<char, 103>{};

и это может сработать. Но это много ручной работы, и она может измениться, когда я изменю систему, добавлю новых участников и т. Д.

Есть ли более автоматический способ сделать это? или некоторые соглашения, которым нужно следовать, чтобы сделать эту проблему менее болезненной

...