0

I have a function that returns a void*. Right now, when this function is completed, a UINT16* array is returned as the void*. The UINT16 array is created at the start of the method, but now I need a way to determine the type of array and create that type instead. For example, some data processing occurs and determines that an array of type int should be created, so an int array is created and returned. Other types like double and byte can also be created.

How do I go about achieving this?

My current code has

UINT16* data_out = new UINT16[arraySize];   

I know I can create a large if/else or switch statement, but I'm wondering if there is a better way.

Roka545
  • 3,404
  • 20
  • 62
  • 106

4 Answers4

1

Something like that perhaps ?

This will not work, but thanks for the upvote. In fact it could work, but you'll have to know the type returned by Foo to be able to use it. But the type is determined inside Foo, that's a serious conception drawback. You should rethink the way you want this to work.

    enum class ArrayType
    {
        Int,
        Double
    };

    template <typename T>
    T* CreateArray(size_t size)
    {
        T* t = new T[size];
        return t;
    }

    void* Foo(param1, param2, etc..)
    {
        size_t size;
        ArrayType type;

        .. Do things to determine the type

        switch(type)
        {
            case ArrayType::Int:
                return CreateArray<int>(size);

            case ArrayType::Double:
                return CreateArray<double>(size);

            default:
                return 0;
        }

        return 0;
    }
nikau6
  • 922
  • 9
  • 16
0

Uhm... sorry if this is more of a question than a comment... :| I can't comment rn.

If you want a core solution, you could create a linked list class that has different type outlets. Basically, instead of having just an UINT_64* next;, you would have:

int* nextInt;
double* nextDouble;

And so on and so forth. Then, if you want to tag a double along, you could just use the nextDouble outlet. To find which outlet to go to, just check if the int is pointing to anything; if not, go next. I know this seems like a REALLY annoying and bulky option, but I suppose it does the job.

Daneolog
  • 286
  • 1
  • 2
  • 13
0

Void * functions can be fun and do some very interesting things... (Sorry for linking a previous answer of mine, but it's the first example which came to me.) But they aren't safe, and have zero type checking...

So in your case, you only need a simple template function, and the auto keyword. Something like:

#include <iostream>
#include <iomanip>

template <typename T>
T * returnAnArray (int size) {
    T * data_out = new T[size];
    return data_out;
}

int main() {
    int size = 3;
    auto array = returnAnArray<double>(3);

    for(int i=0;i<size;++i)
        array[i] = 0;

    for(int i=0;i<size;++i){
        std::cout << std::setprecision(2);
        std::cout << array[i] << std::endl;
    }

    delete [] array;

    return 0;
}

I did have some fun, and did create a void * function:

template <typename T>
void * returnVoidPointerToArray(int size) {
    return new T[size];
}

The function, when used, must be cast for it could return something:

auto chArray = (char*)returnVoidPointerToArray<char>(size);

But the output looks like:

5.00
5.00
5.00
ggg 
ggg 
ggg 
Program ended with exit code: 0

Note how double are a single value, but the same function also initialized a 2d array of characters... Cool, right? Albeit, it's a dirtier, different way of templating functions.

And, like the commenter said, probably a good idea to use unique pointers. :)


And like the other commenter said, I cast the array to char* and got a char* array. :)

NonCreature0714
  • 5,744
  • 10
  • 30
  • 52
  • "but the same function appears to have initialized a 2d array of characters... " - that would be because you cast the result to `char *`, no? – davmac Jan 12 '17 at 01:43
0

I'm not sure why you have to use a practically untyped return value using void*, but let's suppose that there are reasons for it.

There are actually two issues, namely creating the array and using it then.

When creating an array of different types based on some logic, you somehow have to deal with if or switch(); how else would you express the logic determining the desired result type? But, if you like, you could also use something like result = malloc(nrOfItems*sizeOfItem), and determine sizeOfItem on any logic you like, even based on arithmetic calculations.

The more interesting or critical thing is how the caller shall use the result of the respective function, as accessing the elements of an array requires knowledge about the type or the size of the elements in it.

Suppose, for example, the following code:

void* getSomeItems() {
  if (std::rand() > 100000)
    return new char[200];
  else
    return new double[200];
}

int main() {
  void* someItems = getSomeItems();
  double c = ((double*)someItems)[199];  // Critical!
  // how shall we know if element type is double?
  // if rand() decided to create items of type char,
  // this code accesses non allocated memory
  ...

So, unless your function can give back the information on which type has been created (and actually also the size of the array), the return value is almost needless.

I'd suggest not to use void* for this. If you know the type before calling the function, you could use templates, vectors, or other things. If you do not know type and/or size before calling, return a structure that - besides the allocated array - also provides type/size information.

BTW: do not forget to delete[] / free the result at the end.

Stephan Lechner
  • 34,891
  • 4
  • 35
  • 58