考虑以下代码:
#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在_上为minPointer生成的程序集
minPointer(void*, void*):
mov rax, QWORD PTR [rsp-8]
ret它显然不执行代码创建者的意图。是这段代码引起了UB还是GCC(8)的错误?
发布于 2018-09-17 19:07:28
这是UB,但不是因为你可能认为的原因。
std::minmax()的相关签名是:
template<类T> std::pair minmax( const T& a,const T& b );
在本例中,pair是对uintptr_t const的一对引用。我们所指的实际对象在哪里?没错,他们是在最后一行上创造的临时人员,已经超出了范围!我们有悬空的推荐信。
如果你写:
return std::minmax(
reinterpret_cast<std::uintptr_t>(first),
reinterpret_cast<std::uintptr_t>(second)
).first;然后,我们没有任何悬空引用,您可以看到gcc生成了适当的代码:
minPointer(void*, void*):
cmp rsi, rdi
mov rax, rdi
cmovbe rax, rsi
ret或者,您可以显式地将pair类型指定为std::pair<std::uintptr_t, std::uintptr_t>。或者干脆完全避开这对和return std::min(...);。
就语言细节而言,由于[expr.reinterpret.cast]/4,允许将指针转换为足够大的整数类型,并且保证std::uintptr_t足够大。所以一旦你解决了悬空的参考问题,你就没事了。
发布于 2018-09-17 19:06:42
reinterpret_cast有很好的定义。问题是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;
}https://stackoverflow.com/questions/52374048
复制相似问题