考虑以下代码:
#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;
}
以及GCC8在-O3上生成的程序集
https://godbolt.org/z/qWJuV_代表minPointer
:
minPointer(void*, void*):
mov rax, QWORD PTR [rsp-8]
ret
显然不符合代码创建者的意图。这段代码会导致某些UB还是GCC(8)错误?
答案 0 :(得分:22)
这是UB,但这不是您可能会想的原因。
std::minmax()
的相关签名是:
a = int(input("Enter first number")) b = int(input("Enter second number"))
在这种情况下,您的template< class T >
std::pair<const T&,const T&> minmax( const T& a, const T& b );
是对pair
的一对引用。我们要引用的实际对象在哪里?是的,它们是在最后一行创建的临时文件,已经超出范围!我们有悬而未决的参考文献。
如果您写过:
uintptr_t const
然后我们没有任何悬挂的引用,您会看到gcc生成了适当的代码:
return std::minmax(
reinterpret_cast<std::uintptr_t>(first),
reinterpret_cast<std::uintptr_t>(second)
).first;
或者,您可以将minPointer(void*, void*):
cmp rsi, rdi
mov rax, rdi
cmovbe rax, rsi
ret
的类型显式指定为pair
。或者只是完全避开该对并std::pair<std::uintptr_t, std::uintptr_t>
。
就语言细节而言,由于[expr.reinterpret.cast]/4,您可以将指针转换为足够大的整数类型,并且可以保证return std::min(...);
足够大。因此,一旦解决了悬而未决的参考问题,就可以了。
答案 1 :(得分:13)
reinterpret_cast
的定义很明确。问题在于the type of const auto pair
是const 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;
}