Is strict aliasing rule violated in this code?

Viewed 78

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?

0 Answers
Related