【问题标题】:Does reinterpret_cast lead to undefined behavior?reinterpret_cast 会导致未定义的行为吗?
【发布时间】:2016-09-04 05:53:00
【问题描述】:

我有一个类模板 A,其中包含一个指针容器 (T*):

template <typename T>
class A {
public:
   // ... 
private:
   std::vector<T*> data;
};

还有一堆函数,比如:

void f(const A<const T>&);
void g(const A<const T>&);

可以通过从A&lt;const T&gt;A&lt;T&gt; 的转换来调用这些函数吗?

A<double> a;
... 
auto& ac = reinterpret_cast<const A<const double>&>(a);
f(ac);

我很确定这段代码有未定义的行为。

在现实生活中使用此类转换是否危险?

【问题讨论】:

  • 如果是UB,在现实生活中使用它们肯定是危险的。不过,这听起来有点像 XY 问题。
  • 依赖 UB 总是很危险的,即使 “它在现实世界中有效”。想想 Qt-5、Chromium、KDevelop 等项目,它们被 gcc6 破坏了,因为它们使用了一些 this == nullptr 废话。
  • @Holt 可能是一个不可更改的界面。
  • 您应该阅读标准中的5.2.10 Reinterpret cast 部分:open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4582.pdf
  • @erip 我已经更新了这个问题。您有解决问题的建议吗?

标签: c++ templates reinterpret-cast


【解决方案1】:

虽然reinterpret_cast 本身可能是未指定的行为,但在完成转换后尝试访问参数是未定义的行为。

N3337 [basic.lval]/10: 如果程序尝试通过以下类型之一以外的 glvalue 访问对象的存储值,则行为未定义

——对象的动态类型,

——对象动态类型的 cv 限定版本,

——与对象的动态类型类似(定义见 4.4)的类型,

——对象的动态类型对应的有符号或无符号类型,

— 有符号或无符号类型,对应于动态类型的 cv 限定版本 对象,

— 聚合或联合类型,在其元素中包含上述类型之一或非 静态数据成员(递归地包括子聚合的元素或非静态数据成员) 或包含联合),

——对象动态类型的(可能是 cv 限定的)基类类型,

— char 或 unsigned char 类型。

你的例子不是上述的。

【讨论】:

  • 并且在事物上调用任何非静态成员函数都会违反 [class.mfct.non-static]/2,即使它不访问类成员也是如此。如果以任何方式使用结果引用,则几乎到处都是 UB。
【解决方案2】:

由于A&lt;double&gt;A&lt;const double&gt; 是不相关的类型,它实际上是未指定的(最初我认为是未定义的)行为,因此是的,在现实生活中使用它是一个坏主意:你永远不知道什么系统或编译器) 你可以移植到那个改变行为是奇怪的方式。

参考:

5.2.10/11:

T1 类型的左值表达式可以转换为“reference to T2”,如果“指向 T1 的指针”类型的表达式可以显式 使用 reinterpret_cast 转换为“指向 T2 的指针”类型。那 也就是说,参考转换 reinterpret_cast(x) 具有与 转换 *reinterpret_cast(&x) 与内置 & 和 * 运算符(对于 reinterpret_cast(x) 也是如此)。

所以他们已将我们重定向到更早的第 5.2.10/7 节:

对象指针可以显式转换为对象指针 一种不同的类型。 ... ... 转换类型的纯右值 “指向 T1 的指针”指向类型“指向 T2 的指针”(其中 T1 和 T2 是 对象类型和 T2 的对齐要求没有 比 T1 更严格)并返回其原始类型产生 原始指针值。任何其他此类指针的结果 转换未指定。

如果 fg 是适用于容器的算法,那么简单的解决方案是将它们更改为适用于范围(迭代器对)的模板算法。

【讨论】:

  • 我同意,但在这种情况下,我无法在标准 wrt UB 中看到任何内容。你有参考吗?
  • @erip 它打破了严格的别名,对吧?所以就算两者的布局一样,反正都是UB。
  • @MarkB 我仍然认为这是[basic.lval]/10下的UB(至少如果OP继续访问参数)。
  • @MarkB 我害怕这个。我已经更新了这个问题。你能就此提出一些建议吗?
猜你喜欢
  • 2017-11-04
  • 2014-08-11
  • 1970-01-01
  • 2013-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-17
  • 2022-11-16
相关资源
最近更新 更多