Как я могу избавиться от этого дополнительного уровня косвенности?

#c #casting

#c #Кастинг

Вопрос:

Я бы хотел избавиться от этого дополнительного уровня косвенности, поскольку это будет критично для производительности. В частности, массив с именем ‘componentPoolsArray[8]’, в нем хранятся указатели, указывающие на динамически выделяемые пулы. Я бы хотел встроить объекты пула непосредственно в массив, но это будут объекты пула разных типов. Они будут отличаться только типом внутреннего указателя, хранящегося в векторе, а не размером, вот почему я думаю, что мог бы привести или что-то в этом роде:

 struct HomogenousComponentPoolBaseClass {};

template <typename T_Component>
struct HomogenousComponentPool : HomogenousComponentPoolBaseClass
{
    std::vector<T_Component> componentPool;
};

struct ComponentTypeA { int component_A_Member; };
struct ComponentTypeB { int component_B_Member; };
struct ComponentTypeC { int component_C_Member; };

HomogenousComponentPoolBaseClass* componentPoolsArray[8]; // Pointers to component pools, will be heap-allocated
// The only reason I used inheritance here is so I could get it to compile by
// declaring pointers to a base class


int main()
{
    // Create new pool of ComponentTypeA
    componentPoolsArray[0] = new HomogenousComponentPool<ComponentTypeA>;

    // Create a new component in that pool
    static_cast<HomogenousComponentPool<ComponentTypeA>*>
        (componentPoolsArray[0])->componentPool.push_back(ComponentTypeA());

    // Access the first component object from that pool
    static_cast<HomogenousComponentPool<ComponentTypeA>*>
        (componentPoolsArray[0])->componentPool[0].component_A_Member;
} 
 

Поэтому я хотел бы встроить ‘class HomogenousComponentPool<T_Component>’ непосредственно в ‘componentPoolsArray[0]’. Насколько я понимаю, я могу сделать это несколькими способами, но я не уверен, какой из них лучше и даже безопасен ли вообще:

 template <typename T_Component>
struct HomogenousComponentPool // No inheritance
{
    std::vector<T_Component> componentPool;
};

struct ComponentTypeA { int component_A_Member; };
struct ComponentTypeB { int component_B_Member; };

HomogenousComponentPool<char> componentPoolsArray[8]; // The class is built directly into the array.
        // Here I've selected 'char' as the template type, which means that HomogenousComponentPool
// will have std::vector<char> as the componentPool. Since the vector should only store pointers
// then I figured casting to another type won't matter.



int main()
{
    // Create new pool of ComponentTypeA directly into array
    componentPoolsArray[0] = HomogenousComponentPool<char>();

    // Create a new component in that pool
    // I can either cast the outside class
    reinterpret_cast<HomogenousComponentPool<ComponentTypeA>amp;>
        (componentPoolsArray[0]).componentPool.push_back(ComponentTypeA());
    // Or the inside std::vector
    reinterpret_cast<std::vector<ComponentTypeA>amp;>(componentPoolsArray[0].componentPool).push_back(ComponentTypeA());
    
}
 

Является ли это законным кодом? Я думал об использовании нескольких методов, включая указатели void, но я не знаю, как я могу сделать это безопасно. Я бы сделал это только в том случае, если бы выступление было действительно важным

Комментарии:

1. Не хочу перескакивать на пользователя с более чем 8000 репутациями, но … проводили ли вы какое-либо тестирование производительности приложения, чтобы убедиться, что именно здесь необходима оптимизация? Иногда преждевременная оптимизация действительно является корнем всего зла.

2. Это похоже на преждевременную оптимизацию. Если вы так сильно заботитесь о perf, держу пари, вы можете сэкономить гораздо больше, чем косвенное обращение с указателем, используя другие методы. Но, допустим, вы пишете код так быстро, что дополнительная косвенность фактически снижает производительность. В подобных случаях иногда вам просто нужно нарушить безопасность типов. Не такая уж большая проблема, ИМО, если она хорошо инкапсулирована, чтобы void* не просачивалась за пределы непосредственной области, в которой она необходима. Распределители памяти обычно хранят память в виде массивов unsigned char и при необходимости приводят к нужному типу.

3. Второй способ небезопасен. A vector<char> — это не a vector<something_else> . (Хотя на практике это, вероятно , работает, гарантии нет. Вам также нужно вручную очистить вектор.) Что могло бы работать лучше, так это использовать объединение, либо вектор объединений, либо объединение векторов (что и пытается сделать ваш второй способ, но тогда он будет использовать надлежащую поддержку языка).

4. Возможно, стоит взглянуть на std::variant .

5. @Tumbleweed53 Только второй? Но первое приведение — это приведение T<char> к T<ComponentTypeA> , это также не тот тип класса, к которому я его привел. Есть разница с std::vector? Дело в том, что если я приведу внешний класс вместо std::vector, компилятор будет обрабатывать этот std::vector<char> как std::vector<something_else> в любом случае, нет?