Using Void Pointers and Generics with the C++ Programming Language

C++ programming language is currently a widely used powerful language, which allows for Object Oriented Development with Classes, and also has advanced features such as the Standard Template Library (STL) and also the use of Generics. Not only is it fully Object Oriented, but C++ also allows for low level memory management, and is backwardly compatible with the C programming language.

C++ is particularly well suited for large, complex systems development. Currently, it is the main software platform for the F-35 Joint Strike Fighter, which is the worlds most technologically advanced aircraft. Also, C++ is the main programming language for the NASA SLS Artemis Rocket launch systems, which will carry astronauts to the Moon and Beyond to Mars.


The F-35 Joint Strike Fighter, also known officially as the  Lightning II, is manufactured by Lockheed Martin in a joint partnership with the USA Department of Defense and various USA Allies, such as the United Kingdom, Australia, Canada, Norway, and others. It is the most technologically advanced aircraft ever made. Its software is primarily C++.





The NASA SLS Artemis Rocket is the next generation heavy lift rocket that will carry astronauts to the Moon and beyond to Mars. The rocket consists of two solid rocket boosters and a cryogenic fuel main engine. It will be the largest rocket ever made by the USA and NASA. The launch software for the SLS Artemis rocket is primarily C++.


NASA SLS Artemis Rocket Video CLICK HERE.




One thing I encountered in past software work I did, was the use of VOID Pointers (VOID*). At first I was a little confused by them, and did some research, void pointers are primarily a thing that was used with the C programming language, and were used when the developer was unsure of what the type for a particular variable would be during his development. Also, memory allocation in C with the malloc command always returns a void pointer, which C programmers normally cast to another type right after the method is called. Void pointers have the following properties.

  • Do not have a type, are typeless, but can hold the memory address of another variable
  • A void pointer can point to objects of any type
  • Cannot be dereferenced, since the computer has no idea of the amount of memory taken up
  • Can only be dereferenced after being cast as another variable type
  • Cannot have pointer arithmetic done on them
  • Although some compilers allow deleting a void pointer that points to dynamically allocated memory, doing so should be avoided, as it can result in undefined behavior.
As part of the Department of Defense Joint Strike Fighter Project, a document was released to the public domain on standards for safety-critical C++ software, the F-35 Joint Strike Fighter C++ Coding Standards Document.

F-35 Joint Strike Fighter C++ Coding Standards Document CLICK HERE

According to this document, void pointers and cast of variables to other types SHALL not be used in safety-critical C++ software. In this blog post I will show us how to work with and manage void pointers, and also detail how C++ has replaced void pointers with generic programming with templates. I will show example code of working with both void pointers and also generic type templates.

First we will start with our include files for void pointers and template generics for our example C++ program.


Next, we will declare some integer, float, and char string variables, and also our void pointer, to use in our example.


Also, not a part of our example program for this blog post, here is an example of how a void pointer is returned by memory allocation using MALLOC command in C and then immediately cast to another type.


Then in our next section of code for our example program, we will demonstrate setting the void pointer variable to the memory address of another variable, and then show to cast it to another variable type with two different methods, using the C++ STATIC CAST method, and also doing a C-style cast as well. Take note, it is far safer and much better software development to use a C++ static cast instead of a C-style cast.



This is what our output will look like after running the example application for void pointers:


Note how the memory addresses for each variable are sequential and occupy the same area in computer memory, this is a good sign that the C++ compiler is compiling machine code that efficiently uses computer memory.

These are good examples of how you would use void pointers in C++ development. However, in C++ there is feature that provides the same functionality as void pointers, but is better to use and allows for object oriented development, which C does not allow. This feature is called generic programming and allows the use of generic class templates and generic function templates, which allow for type-independent development. In our next code examples, we will show to do C++ generic programming.

First, we will define a template function in our C++ code, outside of the main() method, like the following:


Note that there is not a specific type for the Maximum() function parameter, but instead a generic variable called T that can be used for any type.

Next we will declare variables of different type and call the Maximum() generic function template with them to determine which one is the largest. Note we are using the same function with different types of variables. This is the essence of generic programming in C++, and is a powerful feature for code reusability.



This is what our output will look like after running our example C++ program.


Next, we will define a class template for a class to be used with generic programming in C++. Enter the following code outside of our main method to define our class template. note we are reusing the generic T type, and not a specific type of variable. Note that in the outputList() method, we are using a vector iterator to loop through the elements, in this case the TYPENAME keyword must be used since it is a generic iterator.


Then we will place the following code in our main() method to instantiate objects of type ElementList, and also to output the results of using our generic class template. Note once again we are using only one class for different types of variables, called generic programming.


This is what our output will be after running our example C++ program with generic class template.



Here is a copy and pastable listing of our entire C++ example application.

 // CPPTemplatesPointers.cpp - By Michael G. Workman
 //
 // This C++ console application displays usage of VOID pointers and generic templates
 //
 // This example application is freely distributable under terms of MIT open source license

 #include <iostream>
 #include <string> 
 #include <vector>
 #include <cstdlib>

 using namespace std;

 // class template for generic programming
 template <class T>
 class ElementList {
     private:
       vector<T> elements;

     public:
       void addElement(T const&); 
       T getLastElement() const;
       void outputList();
 };

 // addElement method
 template <class T>
 void ElementList<T>::addElement(T const& element) {
     elements.push_back(element);
 }

 // getLastElement method
 template <class T>
 T ElementList<T>::getLastElement() const {

     // return last element
     return elements.back();
 }

 // output ElementList elements
 template <class T>
 void ElementList<T>::outputList() {

     cout << "ElementList elements: ";
     for (typename vector<T>::iterator it = elements.begin(); it < elements.end(); it++) {
       cout << (*it) << " ";
     }
     cout << endl << endl;
 }

 // we use a function template for generic programming
 template <typename T>
 T const& Maximum(T const& a, T const& b)
 {
     if (a > b) return a;
     if (b > a) return b;
 }

 int main()
 {
     // declare vars
     int nNumber = 10;
     float fNumber = 10.01;
     char cCharArray[] = "This is an example C++ application.";

     // void pointer
     void* ptrVoid;

     // set void pointer to address of integer number, then cast to integer so it can be dereferenced
     ptrVoid = &nNumber;
     cout << endl << "Void pointer to integer address: " << ptrVoid << "\n"
          << "dereferenced value after static cast: " << *static_cast (ptrVoid) << endl
          << "dereferenced value after C-style cast: " << *((int*)ptrVoid) << endl << endl;

     // set void pointer to address of float number, then cast to float so it can be dereferenced
     ptrVoid = &fNumber;
     cout << "Void pointer to float address: " << ptrVoid << endl
          << "dereferenced value after static cast: " << *static_cast (ptrVoid) << endl
          << "dereferenced value after C-style cast: " << *((float*)ptrVoid) << endl << endl;

     // set void pointer to address of char array string, then cast to dereference
     // note with char arrays we do not dereference the pointer, but the non-pointer name of the array
     ptrVoid = &cCharArray;
     cout << "Void pointer to char array address: " << ptrVoid << endl
          << "dereferenced value after static cast: " << static_cast (ptrVoid) << endl 
          << "dereferenced value after C-style cast: " << (char*)ptrVoid << endl << endl;

     // after the advent of generics in C++
     // void pointers, a holdover from C programming, were no longer needed

     // vars to use with function template
     int x = 11;
     int y = 13;
 
     float i = 10.56;
     float j = 14.32;

     string k1 = "C++";
     string k2 = "Application";

     // output the results
     cout << "Maximum integer x or y: " << Maximum(x, y) << endl << endl;
     cout << "Maximum float i or j: " << Maximum(i, j) << endl << endl;
     cout << "Maximum string k1 or k2: " << Maximum(k1, k2) << endl << endl;

     // vars to use with class template
     ElementList<string> strList;
     ElementList<float> fList;
     ElementList<int> nList;

     // add string values to ElementList string object
     strList.addElement("C++");
     strList.addElement("Object Oriented");
     strList.addElement("Application");

     // add float values to ElementList float object
     fList.addElement(3.14);
     fList.addElement(13.1);
     fList.addElement(26.2);

     // add integer values to ElementList int object
     nList.addElement(3);
     nList.addElement(11);
     nList.addElement(27);

     // get the most recent string element
     cout << "String List last element: " << strList.getLastElement() << endl << endl;

     // get the most recent float element
     cout << "Float List last element: " << fList.getLastElement() << endl << endl;

     // get the most recent integer element
     cout << "Integer List last element: " << nList.getLastElement() << endl << endl;

     // output the string list
     strList.outputList();

     // output the integer list
     nList.outputList();

     // output the float list
     fList.outputList();

     return 0;
 }
I hope these examples have been very helpful for you to understand void pointers and generic programming in C++. Generic programming is a powerful feature of the C++ programming language that allows for code reusability and simplicity.

This example program is also stored in my GitHub version control at the following link.

CPPTemplatePointers.cpp

 If you have any questions about CC++Microsoft C# .NET, and/or Microsoft Azure Cloud, please feel free to contact me by email at michael DOT g DOT workman AT gmail DOT COM

Also feel free to review my Curriculum Vitae at http://www.michaelgworkman.com


Comments

Popular Posts