reinterpret_cast会导致未定义的行为吗?

Ser*_*gei 8 c++ templates reinterpret-cast

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

template <typename T>
class A {
public:
   // ... 
private:
   std::vector<T*> data;
};
Run Code Online (Sandbox Code Playgroud)

和一堆功能,如:

void f(const A<const T>&);
void g(const A<const T>&);
Run Code Online (Sandbox Code Playgroud)

是否可以将呼叫通过铸造这些功能从A<const T>A<T>

A<double> a;
... 
auto& ac = reinterpret_cast<const A<const double>&>(a);
f(ac);
Run Code Online (Sandbox Code Playgroud)

我很确定这段代码有不确定的行为.

在现实生活中使用这种转换是危险的吗?

Mar*_*k B 6

作为A<double>A<const double>不相关类型,它实际上未指定的(原本我以为未定义)行为和相应的是这是一个坏主意,在现实生活中使用:你永远不知道什么系统(S)或编译器(S),你可以移植到这种变化的行为是奇怪的方式。

参考:

5.2.10/11:

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

所以他们把我们重定向到了之前的 5.2.10/7 节:

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

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

  • @erip 它打破了严格的别名,对吗?所以就算两者的布局一样,反正都是UB。 (4认同)
  • @MarkB 我仍然认为这是 `[basic.lval]/10` 下的 UB(至少如果 OP 继续访问参数)。 (4认同)

Tar*_*ama 5

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

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

- 对象的动态类型,

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

- 与对象的动态类型类似的类型(如4.4中所定义),

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

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

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

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

- char或unsigned char类型.

你的例子不是上述例子.