-
Notifications
You must be signed in to change notification settings - Fork 134
Replace all remaining instances of reinterpret_cast with std::bit_cast #290
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Sorry for interjecting, but isn't cppreference doesn't have a single example of using it to replace edit: |
No, std::launder will not be needed for std::bit_cast. The reason that you need std::launder for reinterpret_cast is that reinterpret_cast is nothing more than an instruction to the compiler to ignore the type system for a moment. But the compiler is still free to perform optimizations that rely on the assumption that the thing pointed to is what it used to be rather than the reinterpretation. By contrast, std::bit_cast is a much more invasive operation that prohibits such optimizations. In fact, we have had a weird problem, where std::launder in combination with reinterpret_cast led to weird behaviour, but only for GCC 12 and only under certain compiler settings. These problems went away when we started using std::bit_cast in these places. |
The comment you are quoting only refers to instances where things are being cast as a void pointer, something you should never do. |
The crux is In the suggested change, it means it creates a It is not even guaranteed that the value representation of an By contrast,
A (very unlikely but conforming afaik) implementation could use little-endian for some pointers and big-endian for others. In that case, |
@spectras, the problem is that in theory std::launder(reinterpret_cast(...)) should do the trick, but in practice we have had issues. Specifically, we had a tuple implementation that used std::launder(reinterpret_cast(ptr + i)). For GCC 12 (and only GCC 12, other compilers and GCC versions were fine) this led to a weird bug under some very specific compiler flags. Basically, ptr + i was transformed to just i. The problem could be solved by simply removing std::launder or by using std::bit_cast. I am fairly certain that this is in fact a bug in GCC 12. So how do you deal with this? In theory, std::launder(reinterpret_cast(...)) should be fine. In practice, it is not, but std::bit_cast is. |
@spectras and @GregTheMadMonk , what are your thoughts on this solution? template <class T1, class T2>
inline T1 ptr_cast(T2* _ptr) {
return static_cast<T1>(static_cast<void*>(_ptr));
}
template <class T1, class T2>
inline T1 ptr_cast(const T2* _ptr) {
return static_cast<T1>(static_cast<const void*>(_ptr));
}
...
T& get_t() noexcept { return *ptr_cast<T*>(t_or_err_.data()); }
const T& get_t() const noexcept {
return *ptr_cast<const T*>(t_or_err_.data());
}
Error& get_err() noexcept {
return *ptr_cast<Error*>(t_or_err_.data());
}
const Error& get_err() const noexcept {
return *ptr_cast<const Error*>(t_or_err_.data());
} In my view this most certainly isn't UB, because it is never UB to static_cast as pointer to a void* and it is never UB to static_cast a void* to some other type. |
I am closing this in favour of #298. |
No description provided.