Click here to Skip to main content
15,884,176 members
Articles / Desktop Programming / Win32

The Power of void*

Rate me:
Please Sign up or sign in to vote.
2.83/5 (10 votes)
23 Dec 2009CPOL2 min read 28.8K   6   21
Briefly explains one of the powerful usages of the data type void*.

Introduction

In every business problem that we try to solve using any programming language, we will have to hold and manipulate various data types such as int, float, double, char, etc. Most of the time, we also have to manipulate a number of user-defined data types. How we group different data types in memory is a design choice. If we define a data type that can hold any data type, then it would result in a clean and extensible code.

Apart from the automatic variables that will be used for temporary purposes, the real data that we manipulate will always be kept in memory that is allocated in heap. The use of heap memory is because we don't know the size of data that will be coming as input, at runtime. This article explains how to hold and manipulate different data types that are allocated in heap, as a single data type.

One strategy that is followed here is that any type of data is kept as an array of that type. This is because, in order to hold any data type as a void*, we need to play with pointers. The advantage is that, basically, any pointer type can be kept in a void pointer. As we know, there are basically two types of data: numeric and string. Here, any numeric data can be handled using a single pointer. For strings, we need a double pointer. Since there will be multiple strings and since each string itself is an array, we need a double pointer.

The following sections briefly explain each step of implementing a generic data type using a void pointer.

Define an enum for Data Types

As the first step, we need to define an enum that can meaningfully define each data type that we are going to handle.

C++
enum GENERIC_DATA_TYPE
{
   GENERIC_TYPE_NONE = 0,
   GENERIC_TYPE_INT,
   GENERIC_TYPE_SHORT,
   GENERIC_TYPE_DOUBLE,
   GENERIC_TYPE_CHAR,
};

We can also define enums for any user-defined data type.

Defining a Generic Data Type

As the second step, we need to define a data type that can hold any type of data.

C++
struct GENERIC_DATA
{
   GENERIC_DATA_TYPE m_DataType;
   UINT              m_DataSize;
   void*             m_ptrData;
};

All the members of the structure are self explanatory.

Using the Code

The following is a sample program that makes use of the above defined GENERIC_DATA:

C++
#include "windows.h"
#include "vector"

using namespace std;

enum GENERIC_DATA_TYPE
{
   GENERIC_TYPE_NONE = 0,
   GENERIC_TYPE_INT,
   GENERIC_TYPE_SHORT,
   GENERIC_TYPE_DOUBLE,
   GENERIC_TYPE_CHAR,
};

#define SAFE_ARRAY_DELETE( ptrArray ) \
delete[] ptrArray;\
ptrArray = 0;

struct GENERIC_DATA
{
   GENERIC_DATA_TYPE m_DataType;
   UINT              m_DataSize;
   void*             m_ptrData;

   GENERIC_DATA() : m_DataType( GENERIC_TYPE_NONE ),
                    m_DataSize( 0 ),
                    m_ptrData( 0 )
   {
   }

   ~GENERIC_DATA()
   {
       CleanMemory();
   }

   bool CleanMemory()
   {
       try
       {
           switch( m_DataType )
           {
               case GENERIC_TYPE_INT:
               {
                   int* ptrInt = reinterpret_cast<int*>( m_ptrData );
                   SAFE_ARRAY_DELETE( ptrInt );
                   break;
               }
               case GENERIC_TYPE_SHORT:
               {
                   short* ptrShort = reinterpret_cast<short*>( m_ptrData );
                   SAFE_ARRAY_DELETE( ptrShort );
                   break;
               }
               case GENERIC_TYPE_DOUBLE:
               {
                   double* ptrDouble = reinterpret_cast<double*>( m_ptrData );
                   SAFE_ARRAY_DELETE( ptrDouble );
                   break;
               }
               case GENERIC_TYPE_CHAR:
               {
                   // Since string is kept as an array of string,
                   // we need to iterate each string
                   // and delete.
                   char** ptrString = reinterpret_cast<char**>( m_ptrData );
                   for( UINT uCounter = 0; m_DataSize > uCounter; ++uCounter )
                   {
                        SAFE_ARRAY_DELETE( ptrString[uCounter]);
                   }

                   // Now delete the double pointer.
                   SAFE_ARRAY_DELETE( ptrString );
                   break;
               }
           }
           m_DataSize = 0;
           m_DataType = GENERIC_TYPE_NONE;
           return true;
       }
       catch( ... )
       {
       }
       return false;
   }
}; 


typedef vector<GENERIC_DATA*> GENERIC_DATA_VECTOR;

int main()
{
    GENERIC_DATA_VECTOR vData;
    
    // Allocate memory to hold the data
    GENERIC_DATA* ptrData = new GENERIC_DATA();

    // PUT SOME INTERGERS
    // Of course the array size would be determined at runtime.
    const int INT_COUNT = 10;
    int* ptrIntArray = new int[INT_COUNT]; 

    int nCounter = 0;

    // Fill ptrIntArray with some integers
    for( nCounter = 0; INT_COUNT > nCounter; ++nCounter )
    {
        ptrIntArray[nCounter] = rand();
    }
    // It is verly important to set the correct type here.
    ptrData->m_DataType = GENERIC_TYPE_INT;
    ptrData->m_DataSize = INT_COUNT;
    ptrData->m_ptrData  = ptrIntArray;

    // Now put the data in the vector;
    vData.push_back( ptrData );
    

    // PUT SOME STRINGS
    const int STRING_COUNT = 5;
    char** ptrStringArray = new char*[STRING_COUNT];

    // Fill string array with some string
    const char* STRING1 = "STRING1";
    int nStringLength = 0;
    for( nCounter = 0; STRING_COUNT > nCounter; ++nCounter )
    {
        nStringLength = lstrlen( STRING1 );
        ptrStringArray[nCounter] = new char[nStringLength + 1];
        lstrcpy( ptrStringArray[nCounter], STRING1 );
    }
    ptrData = new GENERIC_DATA();
    // It is verly important to set the correct type here.
    ptrData->m_DataType = GENERIC_TYPE_CHAR;
    ptrData->m_DataSize = STRING_COUNT;
    ptrData->m_ptrData  = ptrStringArray;

    // Now put the data in the vector;
    vData.push_back( ptrData );



    // Now, at a later time we can manipulate each
    // or the required type in the vector as below.
    GENERIC_DATA_VECTOR::iterator DATA_VECTOR_END = vData.end();
    GENERIC_DATA_VECTOR::iterator itrData = vData.begin();
    GENERIC_DATA* ptrDataToProcess = 0;
    for( ; itrData != DATA_VECTOR_END; ++itrData )
    {
        ptrDataToProcess = ( *itrData );

        // Look for string
        if( GENERIC_TYPE_CHAR == ptrDataToProcess->m_DataType )
        {
            char** ptrStringArray = 
               reinterpret_cast<char**>( ptrDataToProcess->m_ptrData );

            // Process the string
            for( nCounter = 0; ptrDataToProcess->m_DataSize > nCounter; ++nCounter )
            {
                printf( "\n %s", ptrStringArray[nCounter]);
            }
        }

        // Look for integer
        if( GENERIC_TYPE_INT == ptrDataToProcess->m_DataType )
        {
            int* ptrIntArray = reinterpret_cast<int*>( ptrDataToProcess->m_ptrData );

            // Process integers
            for( nCounter = 0; ptrDataToProcess->m_DataSize > nCounter; ++nCounter )
            {
                printf( "\n %d", ptrIntArray[nCounter]);
            }
        }

    }

    // Once we finish with the data, iterate the vector and delete each entry.
    DATA_VECTOR_END = vData.end();
    itrData = vData.begin();
    for( ; itrData != DATA_VECTOR_END; ++itrData )
    {
        delete ( *itrData );
    }

    return 0;
}

The above code simply demonstrates the usage of GENERIC_DATA. We can define any complex user defined data type and hold such objects as generic data. If you have any Windows HANDLE of any device or synchronization object, you can make an entry in the enum defined above and manipulate it accordingly. This kind of approach will be very useful for centralized management of data in any project.

Points of Interest

The key point is that, we can basically assign any pointer type to a void pointer. When accessing data, check the data type and use the reinterpret_cast() operator for converting it to the real data type.

History

  • December 23, 2009 - Article posted.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
Shooting for the Moon.

Comments and Discussions

 
QuestionWhy oh why? Pin
jeffb425-Jan-10 7:03
jeffb425-Jan-10 7:03 
AnswerRe: Why oh why? Pin
Nisamudheen5-Jan-10 19:13
Nisamudheen5-Jan-10 19:13 
GeneralMy vote of 2 Pin
jeffb425-Jan-10 6:59
jeffb425-Jan-10 6:59 
GeneralMy vote of 1 Pin
Emilio Garavaglia28-Dec-09 7:53
Emilio Garavaglia28-Dec-09 7:53 
GeneralMy vote of 1 Pin
lusores24-Dec-09 10:07
lusores24-Dec-09 10:07 
GeneralRe: My vote of 1 Pin
Nisamudheen24-Dec-09 14:15
Nisamudheen24-Dec-09 14:15 
GeneralMy vote of 1 Pin
Jimmanuel24-Dec-09 7:26
Jimmanuel24-Dec-09 7:26 
GeneralRe: My vote of 1 Pin
Nisamudheen24-Dec-09 14:07
Nisamudheen24-Dec-09 14:07 
GeneralRe: My vote of 1 Pin
Jimmanuel24-Dec-09 15:27
Jimmanuel24-Dec-09 15:27 
GeneralRe: My vote of 1 Pin
Nisamudheen24-Dec-09 23:07
Nisamudheen24-Dec-09 23:07 
GeneralRe: My vote of 1 Pin
Jimmanuel25-Dec-09 6:44
Jimmanuel25-Dec-09 6:44 
GeneralRe: My vote of 1 Pin
Nisamudheen26-Dec-09 15:23
Nisamudheen26-Dec-09 15:23 
GeneralRe: My vote of 1 Pin
Jimmanuel27-Dec-09 2:52
Jimmanuel27-Dec-09 2:52 
GeneralRe: My vote of 1 Pin
Emilio Garavaglia28-Dec-09 7:51
Emilio Garavaglia28-Dec-09 7:51 
GeneralRe: My vote of 1 Pin
Jimmanuel28-Dec-09 8:39
Jimmanuel28-Dec-09 8:39 
GeneralWOW Pin
persian music24-Dec-09 1:24
persian music24-Dec-09 1:24 
GeneralMy vote of 1 Pin
Tim Craig23-Dec-09 18:23
Tim Craig23-Dec-09 18:23 
GeneralMy vote of 1 Pin
xliqz23-Dec-09 14:12
xliqz23-Dec-09 14:12 
GeneralRe: My vote of 1 [I'm a troll] Pin
ProtoBytes30-Dec-09 6:53
ProtoBytes30-Dec-09 6:53 
Questionobv.? Pin
xliqz23-Dec-09 12:08
xliqz23-Dec-09 12:08 
AnswerRe: obv.? Pin
Nisamudheen23-Dec-09 14:10
Nisamudheen23-Dec-09 14:10 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.