Каков наиболее эффективный способ получить доступ к выровненным символам T & с символа []?

Вчера вечером я работал над этим классом как надёжная оболочка для объектов, выровненных по памяти. У меня есть байтовый массив и математика для доступа к памяти байтового массива для чтения и записи как T, Мне любопытно, однако, как я могу обеспечить наиболее эффективный доступ к согласованным T,

Я пытался использовать публичный T & называется Value который я бы инициализировал к выровненным T в списке инициализатора конструктора. Как это:

template <typename T, size_t alignment = 64>
struct Aligned {
private:
    std::uint8_t bytes[sizeof(T) + alignment - 1];
public:
    T & Value;
    Aligned(T const & value = T()) : Value(*reinterpret_cast<T *>((intptr_t)bytes + (alignment - 1) & ~intptr_t(alignment - 1))) {
        Value = value;
    }
};

Это увеличивает размер класса на sizeof(T *) поскольку T & Value нужно хранить адрес выровненного T,

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

#include <array>
#include <cstdint>

template <typename T, size_t alignment = 64>
struct Aligned {
private:
    std::array<uint8_t, sizeof(T) + alignment - 1> const bytes;
public:
    T const & value() const {
        return *reinterpret_cast<T *>((intptr_t)bytes.data() + (alignment - 1) & ~intptr_t(alignment - 1));
    }
    void value(T const & x) {
        *reinterpret_cast<T *>((intptr_t)bytes.data() + (alignment - 1) & ~intptr_t(alignment - 1)) = x;
    }
    Aligned(T const & x = T()) {
        value(x);
    }
};

Этот подход потребует арифметику указателя и разыменование указателя (я думаю?) Для каждого доступа, но ничего не добавляет к размеру класса.

Есть ли другие подходы или приемы, чтобы получить оба преимущества?

2 ответа

Решение

Я думаю, что вариант 1 выглядит аккуратнее, и я не думаю, что есть какая-то польза от варианта 2.

Однако, если вам нужно знать, что дает вам лучшую производительность, вам действительно необходимо выполнить код таким образом, чтобы можно было измерить производительность. Я или кто-то еще, глядя на код и говоря: "А выглядит лучше, чем В", не годится - компиляторы не предсказуемы на 100%, и иногда выбор "Хорошо выглядит" не лучший выбор. Это то, что я говорю о ВСЕХ постах производительности, и для этого есть веская причина. Я лично испытал это, когда вы смотрите на два фрагмента кода, говоря: "Ну, они будут проходить в одно и то же время, они почти идентичны", но поскольку есть небольшая разница, производительность заметно выше в случае А, чем в случае B (или наоборот).

Убедитесь, что вы не просто тестируете здесь тривиальный случай, вам нужно несколько разных вариантов, таких как структура с большим количеством элементов, большой и маленький массив, а также простой int, long long, double, так далее.

Если у вас есть доступ к C++11, вы можете использовать новое ключевое слово alignas, чтобы компилятор выровнял тип или переменную для вас.

alignas(64) classA myA;
Другие вопросы по тегам