Consider the following two functions:
template<typename T, typename S>
void swap1(T* t, S* s)
{
static_assert(sizeof(T) == sizeof(S));
char tmp[sizeof(T)];
std::memcpy(tmp, t, sizeof(T));
std::memcpy(t, s, sizeof(T));
std::memcpy(s, tmp, sizeof(T));
}
and
template<typename T, typename S>
void swap2(T* t, S* s)
{
static_assert(sizeof(T) == sizeof(S));
char *tc = (char*)t, *sc = (char*)s;
std::swap_ranges(tc, tc + sizeof(T), sc);
}
Which of them violates the strict aliasing rule? Do both of them violate the rule? If both, how to achieve the goal without violation?
All I can see from C++ standard is that, we can use pointers of certain types including char* to point at an arbitrary object, and access its stored value. What does access mean? Is it just read or read+write?
I didn't find an emphatic answer from What is the Strict Aliasing Rule and Why do we care?. Discussion on Hacker News - memcpy certainly violates aliasing rules confused me even more.
But by reading the "memcpy version, compliant to C and C++ specs and efficient" section of Understanding C/C++ Strict Aliasing, it seems at least swap2 is perfectly fine.
Neither implementation violates the strict aliasing rule. The rule prohibits reading or writing
T*viaU*unlessU*ischar*/unsigned char*/std::byte*. Reading and writing throughchar*is perfectly standard C++.Whether the object ends up having some value in the end is a whole another story. I don't think standard guarantees anything unless
TandUare the same type. Maybe barring some arithmetic conversions. But I'm not sure.If you only have a single trivially copyable type
T, [basic.types]/2 says (omitting some details):