On Wed, Jul 12, 2017 at 2:33 AM, Gavin Lambert via Boost
On 11/07/2017 21:30, Andrey Semashev wrote:
You can cast both ways. The casted-from-char pointer can be used as long as the underlying object, in the C++ object model, matches the pointed type. In other words, this is fine:
std::size_t* p1 = new std::size_t[10]; char* p2 = reinterpret_cast< char* >(p1); std::size_t* p3 = reinterpret_cast< std::size_t* >(p2); assert(p1 == p3); p3[0] = 10; // ok
In Beast's case we (and compiler) cannot tell whether the pointers refer to std::size_t objects. For compiler that means it has to assume the objects exist and thus prevent any optimizations that would contradict it.
I'm not an expert, but I believe that strictly according to the standard it is UB to cast from a char* to any other pointer type, regardless.
It's not, according to [expr.static.cast]/13 and [expr.reinterpret.cast]/7.
(It's also important to note that the standard only permits casting to "char*" -- not "unsigned char*" or "uint8_t*".)
As noted above, you can cast between any of these types. It is what you can do with the resulting pointers that is restricted. Character types (and std::byte since C++17 - which, BTW, has unsigned char as the base type) are special because storage and object representation are expressed with these types. See [intro.object]/3, [basic.types]/4. There are also multiple other places where the spec allows to obtain a pointer to storage expressed as a pointer to one of the character types or std::byte.
Having said that, as long as you are careful to only do so with POD types (or at least types that cannot have a vtable) and only when the alignment requirements of the type are met, then most compilers should probably let you get away with it, because it's far too useful functionality to ban outright.
The nature of the type (POD or not) is not significant - all objects obey the same object model.
In the example above, since you're starting with a "real" type and then casting to char* and back you're guaranteed to meet the alignment requirements, so it should be reasonably safe.
You can still run afoul of strict aliasing if you pass both pointers to other methods, however (but passing only one should be safe). Hopefully the compiler is smart enough to notice that they're aliased as long as you stay within the same method.
If you break strict aliasing rules you are in the UB land. The compiler is not required to notice anything - it simply follows the assumption that the rules are not violated. The end result is likely misbehaving code.