Converting a templated data into another templated data

52 Views Asked by At

I have a method returning a templated class and taking as argument another templated class such as :

template <class T, class U>
T caster(U* u)
{
    return reinterpret_cast<T>(u);  
}   

Compiling with an ARM compiler, i get a cast-align error returned by my compiler which understandable because in my example bellow, char and int do not have the same alignment. As i know that reinterpret_cast is not that such of a good practice, i tried the following changes :

template <class T, class U>
T caster(U* u)
{
    T tmp;
    std::memcpy(&tmp, u, sizeof(U));
    return tmp;
}

int main()
{
    int32_t test = 50000;
    auto tmp = caster<char, int32_t>(&test);
    return 0;
}

But this time i get a stack smashing detected error which is equivalent i believe to a kind of overflow.

What am I doing wrong ? Based on 2 unknown types, how can i properly cast U to T taking into account alignment ?

1

There are 1 best solutions below

0
Jan Schultke On BEST ANSWER
T tmp;
std::memcpy(&tmp, u, sizeof(U));
return tmp;

The obvious issue here is that you're copying sizeof(U) bytes into T, even though T may be smaller or larger.

  • if T is larger, it's possible that some bytes of tmp are left indeterminate
  • if T is smaller, you write past the end of tmp
    • stack smashing happens where T = char and U = int32_t because three bytes are written past the end of tmp

If anything, it should be sizeof(T) or sizeof(tmp):

template <class T>
T caster(void* memory) {
    T tmp;
    // It's still possible that we cannot read sizeof(T) bytes from memory,
    // but that's on the caller, and at least we never smash the stack.
    std::memcpy(&tmp, memory, sizeof(T));
    return tmp;
}

Notice that what you're making here is a poor-man's std::bit_cast. It's one of the ways to do type punning in modern C++. reinterpret_cast virtually never is.

See also