I want to know if my code violates strict aliasing rule or anything else. As far as I can see all I'm doing is constructing an object (say an int) in memory. A char* points to the memory. Then I make an int* point to the memory that char* is pointing to. What I do in my code I think is equivalent to this:
char* memory = (char*)malloc(16);
new (memory) int;
int* intptr = (int*)memory;
*intptr = 7; // I can access this pointer
The above looks perfectly fine, but is that only because I constructed an int in the memory buffer? Suppose I did this instead:
char* memory = (char*)malloc(16);
// new (memory) int; // Don't create an int here
int* intptr = (int*)memory;
The above still seems valid because it's no different from a simple C allocation:
int* intptr = (int*)malloc(16);
However how about something like this now:
int* intptr = (int*)malloc(16);
new (intptr) short;
*intptr = 7; // Is this now illegal?
If the above is illegal, then is that because I've 'created' a double at that storage? Even though double is just plain data and in some way isn't even 'created'? I assume that's the same reason why this is illegal:
int* intptr = (int*)new short[16];
*intptr = 7;
Below is my code, I construct an object somewhere in memory and return the memory cast as a pointer to the correct object (ie., the same one that was constructed at that address). It shouldn't matter that essentially I'm casting from char* to another unrelated object, right? Because the correct object was constructed there?
#include <vector>
#include <cassert>
int globalIndexCounter = 0;
template <typename T>
int typeIdx = globalIndexCounter++;
/* Tries to store different types that are indexable, but have to be the same size */
template <int max_size, int element_size>
struct ArrayThatCanStoreDifferentTypes
{
ArrayThatCanStoreDifferentTypes() { memory = (char*)malloc(max_size * element_size); }
template <typename obj_t>
void addObject(const obj_t& obj)
{
int idx = typeIdx<obj_t>;
new (memory + element_size * idx) obj_t(obj);
}
template <typename obj_t>
obj_t& getObject()
{
int idx = typeIdx<obj_t>;
return *(obj_t*)(memory + element_size * idx);
}
char* memory;
};
template <typename T>
struct List
{
std::vector<T> listItems;
};
int main()
{
ArrayThatCanStoreDifferentTypes <16, sizeof(List<int>)> myArray;
myArray.addObject(List<int>{}); // Is constructed at idx 0
myArray.addObject(List<char>{}); // Is constructed at idx 1
myArray.addObject(List<void*>{}); // Is constructed at idx 2
struct mystruct {};
myArray.addObject(List<mystruct>{}); // Is constructed at idx 3
myArray.getObject<List<int>>(); // Get my list of int
myArray.getObject<List<char>>(); // Get my list of char
// These returns of getObject return char*, and I alias it with a pointer to another type, but that's still OK right?
List<int>* ptrAliasingCharPtr = &myArray.getObject<List<int>>();
}
The reason why I think I can alias a char* with a pointer to another type, say a List*, is that the the pointer is pointing to memory/storage where an actual List was constructed. So in this case it isn't violating the strict aliasing rule?