reinterpret_cast bug还是UB?

bar*_*top 15 c++ undefined-behavior language-lawyer reinterpret-cast

考虑以下代码:

#include <cstdint>
#include <algorithm>

std::uintptr_t minPointer(void *first, void *second) {
    const auto pair = std::minmax(
        reinterpret_cast<std::uintptr_t>(first),
        reinterpret_cast<std::uintptr_t>(second)
    );
    return pair.first;
}
Run Code Online (Sandbox Code Playgroud)

并且所产生的组件通过与-O3 GCC8上 https://godbolt.org/z/qWJuV_minPointer:

minPointer(void*, void*):
  mov rax, QWORD PTR [rsp-8]
  ret
Run Code Online (Sandbox Code Playgroud)

这显然不符合代码创建者的意图.这个代码是导致某些UB还是GCC(8)错误?

Bar*_*rry 22

这是UB,但不是你想的原因.

相关签名std::minmax()是:

template< class T > 
std::pair<const T&,const T&> minmax( const T& a, const T& b );
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您pair是一对引用uintptr_t const.我们引用的实际对象在哪里?这是对的,他们是在最后一行创建的临时表已经超出了范围!我们有悬挂参考.

如果你写道:

return std::minmax(
    reinterpret_cast<std::uintptr_t>(first),
    reinterpret_cast<std::uintptr_t>(second)
).first;
Run Code Online (Sandbox Code Playgroud)

然后我们没有任何悬空引用,你可以看到gcc生成适当的代码:

minPointer(void*, void*):
  cmp rsi, rdi
  mov rax, rdi
  cmovbe rax, rsi
  ret
Run Code Online (Sandbox Code Playgroud)

或者,您可以明确指定pairas 的类型std::pair<std::uintptr_t, std::uintptr_t>.或者只是完全回避这对return std::min(...);.


就语言细节而言,由于[expr.reinterpret.cast]/4,您可以将指针转换为足够大的整数类型,并且std::uintptr_t保证足够大.所以一旦你解决悬空参考问题,你就没事了.


Jus*_*tin 13

reinterpret_cast是明确的定义.问题是,返回的类型const auto pairconst std::pair<const std::uintptr_t&, const std::uintptr_t&>什么std::minmax,所以你有悬挂引用.

你只需要摆脱悬挂的引用就可以了:

std::uintptr_t minPointer(void *first, void *second) {
    const std::pair<std::uintptr_t, std::uintptr_t> pair = std::minmax(
        reinterpret_cast<std::uintptr_t>(first),
        reinterpret_cast<std::uintptr_t>(second)
    );
    return pair.first;
}
Run Code Online (Sandbox Code Playgroud)

Godbolt链接