2d float ** или double ** время выполнения массива - PullRequest
0 голосов
/ 03 апреля 2020

Я должен создать массив массива с именем m2DArray. Он имеет 2 строки и 5 столбцов, т.е. размер [2] [5].

Массив может быть float** или double**, что мне известно только во время выполнения.

Поскольку я не знаю тип во время компиляции, я инициализирую его в моих заголовочных файлах как

void **m2DArray;

Затем я создаю функцию шаблона:

template <typename SampleType>
void MyClass::initiliaze2DArray(SampleType** m2DArrayTyped)
{
    m2DArray = new SampleType* [2]; //2 rows
    int32 sizeOfOneCol =  5 * sizeof(SampleType); // 5 cols
    for (int32 row = 0; row < 2; row++)
    {
        m2DArray[row] = new  SampleType [sizeOfOneColumn];
    memset(m2DArray[row], 0, sizeOfOneCol);
    }
}

Затем во время выполнения я решаю между float ** или double ** на основе некоторых логик c в классе и, соответственно, попытаться инициализировать массив 2d.

if (somelogictellsfloat){
   float **mArrayFloat;
   initiliaze2DArray(mArrayFloat);
} 
else {
   double **mArrayDouble;
   initiliaze2DArray(mArrayDouble);
}

Однако при попытке инициализировать этот массив 2d я не могу преобразовать пустоту ** в плавающую ** или двойную ** в моей функции шаблона.

Я получаю следующую ошибку:

ошибка: недопустимое преобразование из 'double ** 'to' void ** 'в строке m2DArray = new SampleType * [2];

Мой вопрос:

Как я могу разыграть ** m2DArray из пустота ** плавать ** или двойная **? Или есть лучший способ создать этот 2d массив во время выполнения.

1 Ответ

1 голос
/ 04 апреля 2020

У вас есть некоторые недоразумения здесь. Самое важное: void** НЕ является обобщенным c указателем. Единственный общий указатель c - void*. Таким образом, ваш тип void** может содержать адрес универсального c void*. Это вам нужно понять.

Итак, независимо от того, сколько измерений будет иметь ваш массив, вы можете присвоить его void*. И позже вы несете ответственность за то, чтобы привести его к нужному вам типу. См .:

    // Create a 5 dimensional array
    char***** dimension5 = static_cast<char*****>( malloc(200));    
    // Assign it to a generic pointer
    void* generic = dimension5;                                     
    // Get the address of the generic pointer
    void** addressOfGeneric = &generic;
    // Now dereference the address of the generic pointer to get back the generic pointer 
    // and cast it to our original type
    char***** dimension5Later = static_cast<char*****>(*addressOfGeneric);
    // Do something with the array
    dimension5Later[0][0][0][0][0] = 'H';

Но, конечно, мы бы никогда этого не сделали. В C ++ мы никогда не должны использовать необработанные указатели для собственной памяти. Мы должны стараться вообще избегать необработанных указателей и работать с умными указателями. Мы не должны использовать malloc, и мы даже не должны использовать new и вместо этого некоторую make_unique -функцию.

Интересно, нужно ли вам это вообще. Потому что вы должны использовать std::vector.

Пожалуйста, смотрите следующее:

    // The dimension of our 2d vector
    constexpr size_t NumberOfRows = 2U;
    constexpr size_t NumberOfColumns = 5U;
    bool somelogictellsfloat{ true };

    // Depending on what to create
    if (somelogictellsfloat) {

        // Create and initialize a 2d vector for floats
        std::vector<std::vector<float>> mArrayFloat(NumberOfRows, std::vector<float>(NumberOfColumns, 0.0));
    }
    else {
        // Create and initialize a 2d vector for doubles
        std::vector<std::vector<double>> mArrayDouble(NumberOfRows, std::vector<double>(NumberOfColumns, 0.0));
    }

Но то, что вы действительно хотите, это использовать абстрактный шаблон фабрики. Если вы не знаете, пожалуйста, прочитайте об этом.

Кстати. Я сделал для вашего оригинального кода минимально воспроизводимый пример. Это вы всегда должны делать в вопросах о SO.

Я исправил некоторые ошибки и сделал его компилируемым. Но, пожалуйста, не используйте

#include <cstring>
#include < cstdlib >
#include <vector>

struct MyClass {

    void** m2DArray;   // Address of a generic pointer
    void* md;
    float** mArrayFloat;
    double** mArrayDouble;
    using int32 = int;

    template <typename SampleType>
    void initiliaze2DArray(SampleType** m2DArrayTyped)
    {
        m2DArrayTyped = new SampleType * [2]; //2 rows
        int32 sizeOfOneCol = 5 * sizeof(SampleType); // 5 cols
        for (int32 row = 0; row < 2; row++)
        {
            m2DArrayTyped[row] = new  SampleType[5];
            memset(m2DArrayTyped[row], 0, sizeOfOneCol);
        }
        md = m2DArrayTyped; // md is now a generic pointer 
        m2DArray = &md;     // and m2DArray is the address of that generic pointer
    }
    // Test function
    void test(bool doFloatAndNotDouble) {
        if (doFloatAndNotDouble) {
            initiliaze2DArray(mArrayFloat);
        }
        else {
            initiliaze2DArray(mArrayDouble);
        }
    }
};
// Driver code
int main() {

    MyClass mc{};
    mc.test(true);
    mc.test(false);
    return 0;
}



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