как статически преобразовать необработанный массив в структуру, которая состоит только из ссылки на массив

У меня есть критически важный для производительности фрагмент кода, в котором оператор должен возвращать обернутую ссылку на необработанный массив:

      struct A{
   float (&p)[32]; // << this is the only attribute of A; you may change the type of p into float* but iff there is no other possible solution.
   // ... here follow member-functions of A
};
struct B{
   float (*p)[32]; // << this is mandatory
   A& operator[](size_t i){ return static_cast<A>(p[i]); } // << critical line
};

Невозможно заменить B массивом A, поскольку B ссылается на данные из необработанного внешнего кода. Я мог бы обойти эту проблему, заменив функции-члены A на функции, не являющиеся членами float[32], но тогда мне пришлось бы реорганизовать значительную часть существующего кода.

Конечно, заброс в критическую линию сделать невозможно. Но я не хочу мириться ни с избыточностью создания массива A, ни с накладными расходами на создание (и, в конечном итоге, уничтожение) экземпляра A для каждого вызова оператора [].

Итак, как это можно сделать? Пожалуйста, предоставьте функционирующий код, который достигает цели с минимальными (в идеале вообще без) накладными расходами.

2 ответа

имеет только один член ссылочного типа. Это чрезвычайно легко построить/разрушить. Он должен иметь те же накладные расходы, что и возврат указателя.

Просто построить новыйAобъект при каждом вызове:

      struct B{
   float (*p)[32]; // << this is mandatory
   A operator[](unsigned i){ return A{p[i]}; } // << critical line
};

И не будет никаких накладных расходов по сравнению с использованием функций, не являющихся членами.float[32]: https://godbolt.org/z/Md6TP7PPP

Оболочку для A можно переназначить в C++20, но создание исходного объекта A также всегда требует инициализации. Это можно сделать с фиктивным массивом.

      #include <memory>

struct B {
    float(*p)[32]; // << this is mandatory
};

struct A {
    inline static float dummy[32]{};
    float(&p)[32]=dummy; // << this is the only attribute of A; you may change the type of p into float* but iff there is no other possible solution.
    // ... here follow member-functions of A
    A() : p(p) {}  // ctor from B
    A(const B& b, size_t index) : p(b.p[index]) {}  // ctor from B
    A(float(&p)[32]) : p(p) {}  // ctor from array ref
    void reset_an_A_from_B(const B& b, size_t index) {
        std::destroy_at(this);  // this is not needed in this example since A is trivially destructable
        std::construct_at(this, A{ b.p[index] });
    };
};


int main()
{
    float external_arrays[2][32]{};
    B b1{external_arrays};     // contains two arrays of 32 floats

    A a(b1,0);  // construct a from b, first (and only) array
    a.reset_an_A_from_B(b1, 1);    // reset a to refer to second array in b

    // alternately, construct an A initialized by the dummy static array
    A a1;
    a1.reset_an_A_from_B(b1, 0);    // then reset a to refer to first array in a B object

    // To use the reference in A
    float x = a1.p[31];
}

Это позволяет при необходимости динамически изменять в коде то, на что ссылается объект A.

Другие вопросы по тегам