I have a structure as below
struct things
{
BOOL_T is_copy; /* is false */
handle1 h1;
handle2 h2;
int n;
void * memory;
};
Sometimes I make a copy of objects of things
in below structure
struct copy_of_things
{
BOOL_T is_copy; /* is true */
handle1 h1; /* I don't need h2 and n here */
void * memory; /* copied from things object and
things object allocates new memory */
int another_member;
};
Also I have an array of structure in a manager that keeps all the things
and copy_of_things
structure living in my program(call it struct things *things_array[SIZE_OF_ARRAY];
). I can not manage 2 arrays because of design requirements(Arrays are similar to hash). To enable this, I made the type of this array as thing *
and changed the type of copy_of_things
as below
struct copy_of_things
{
struct things ths;
int another_member;
};
Now I can read is_copy
member of my array elements and decide whether to interpret it as things
or copy_of_things
.
I feel this is not only inefficient
in terms of memory but ugly
looking.
Solution 2
I also plan to use type of array is struct of type(is_copy) and a union
.
struct things {
BOOL_T is_copy;
union {
struct { /* is_copy = false */
handle1 h1;
handle2 h2;
int n;
void * memory;
} t;
struct { /* is_copy = true */
handle1 h1;
void * memory;
int another_member;
} c;
};
But while reviewing I found this design also ugly.
Solution 3 I plan to keep BOOL_T is_copy;
as first member of both structure and keep array of type BOOL_T
. After reading the content of BOOL_T
I can de-reference my pointer to things or copy_of_things. I am not sure if this is a good solution and provides a well defined behaviour (at higher level of optimization) as same address is interpreted as different types.
Question Is there a better solution for my problem that is portable on any platform.
EDIT
Thank you for the answers. So there are two suggested alternatives.
- Use Unions: Downside of the approach is, it requires more memory for copies. In my case the
sizeof copy_of_things
is significantly smaller thansizeof things
. One workaround would be alloc just enough bytes in which actual object can reside. - Use a common struct and make it first member of both
copy_of_things
andthings
. Here I would end up de-referencing same memory location with 2 types (struct common and struct things or struct copy_of_things). I am not sure that strict aliasing rule won't bite me. - One more solution can be keep first member of both structs as
char is_copy; /* \0 if not a copy, non zero otherwise
and access the pointer only aschar *
orthings *
orcopy_of_things *
.
Still open question
I have seen solution 2 used at many places. Is it strict aliasing rule safe? Is there a better solution to my problems as the code would be compiled on a variety of compilers. Size of reverse mapping array is large so I am avoiding to use a union or a solution that increases the size of reverse mapping. Number of things (and copy) are less, so it is okay to add new data member there.