reinterpret_cast错误还是UB? [英] reinterpret_cast bug or UB?

查看:172
本文介绍了reinterpret_cast错误还是UB?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下代码:

#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_ for minPointer:

and the assembly generated by GCC8 with -O3 on https://godbolt.org/z/qWJuV_ for minPointer:

minPointer(void*, void*):
  mov rax, QWORD PTR [rsp-8]
  ret

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

which clearly does not do what is intended by the code creator. Is this code causing some UB or is it GCC(8) bug?

推荐答案

这是UB,但并非出于您可能会想到的原因.

This is UB, but not for the reason you might think.

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

The relevant signature of std::minmax() is:

template< class T > 
std::pair<const T&,const T&> minmax( const T& a, const T& b );

在这种情况下,您的pair是对uintptr_t const的一对引用.我们要引用的实际对象在哪里?是的,它们是在最后一行创建的临时文件,已经超出范围!我们有悬而未决的参考文献.

In this case, your pair is a pair of references to uintptr_t const. Where are the actual objects we're referencing? That's right, they were temporaries created on the last line that have already gone out of scope! We have dangling references.

如果您写过:

return std::minmax(
    reinterpret_cast<std::uintptr_t>(first),
    reinterpret_cast<std::uintptr_t>(second)
).first;

然后我们没有任何悬挂的引用,您会看到gcc生成了适当的代码:

then we don't have any dangling references and you can see that gcc generates appropriate code:

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(...);.

Alternatively, you could explicitly specify the type of pair as std::pair<std::uintptr_t, std::uintptr_t>. Or just sidestep the pair entirely and return std::min(...);.

就具体语言而言,由于 [expr.reinterpret.cast]/4 ,并且保证std::uintptr_t足够大.因此,一旦解决了悬而未决的参考问题,就可以了.

As far as language specifics, you are allowed to convert a pointer to a large enough integral type due to [expr.reinterpret.cast]/4, and std::uintptr_t is guaranteed to be large enough. So once you fix the dangling reference issue, you're fine.

这篇关于reinterpret_cast错误还是UB?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆