Broad Cast
In applications that transmit data over networks or use persistent objects, casting an object to a char array and vice versa are common operations. Using reinterpret_castor C-style cast for every such conversion is tedious and messy. The infamous "union hack", in spite of its bad reputation, can simplify this task by eliminating explicit cast expressions from your code.
Suppose you have a networking application that receives a variable of type double from a remote client. The variable is received as stream of bytes. Your task is to convert that char array to double, print its value and then store the value in a file. In other words, you need to cast a char array to double and then cast the result back to a char array. The easiest way to do that is to define a union that contains two members; the first member is of type double and the second one is an array of sizeof(double)char:
#include <fstream>
using namespace std;
union hack
{
//both members overlap exactly
double d;
char bytes[sizeof(double)];
} h;
char * getbytes(size_t sz); //reads client data
h.d= *(double*) getbytes(sizeof(double));
cout<<"received the value: "<<h.d<<endl;
ofstream archive("values.dat", ios::binary);
archive.write(h.bytes, sizeof (h.d));
To reconstitute the original double value from the file values.dat, use the union like this:
ifstream archive("values.dat");
archive.read(h.bytes, sizeof (h.d));
cout<<"retrieved value: "<<h.d<<endl;
In simpler words, the union allows you to view the same piece of memory either as a double or as a char array simply by switching between the two union members. Recall that all union members have the same address. To ensure that they also occupy exactly the same number of bytes, calculate the size of the char array using sizeof(type_of_first_member). The union hack eliminates the drudgery of using reinterpret_castin every I/O operation. Notice that the code doesn't use a single cast expression.
Obviously, the next evolutionary step is to replace the union with a union template, thus automating the conversion from an arbitrary type Tto a char array:
template <typename T> union hack
{
T data;
char bytes[sizeof(T)] ;
};
Dare to Be Different
Bad PR and snobbery shouldn't deter you from using features that get the job done quickly, elegantly and often with less bugs and hesitation as witnessed with C++ cast operators. C-style cast has three advantages over C++ style cast:
- It frees you from the confusion between static_cast and reinterpret_cast.
- It can perform two cast operations in a single expression.
The union hack eliminates the clutter and inelegance of recurrent cast expressions.