我有一个类模板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<const T>
到A<T>
的演员来调用这些功能是否可以?
A<double> a;
...
auto& ac = reinterpret_cast<const A<const double>&>(a);
f(ac);
我很确定此代码具有未定义的行为。
在现实生活中使用这种转换是否危险?
答案 0 :(得分:5)
虽然reinterpret_cast
本身可能是未指定的行为,但是在您完成转换后尝试访问参数是未定义的行为。
N3337 [basic.lval]/10:
如果程序试图通过以下类型之一以外的glvalue访问对象的存储值,则行为未定义- 对象的动态类型,
- 对象的动态类型的cv限定版本,
- 与对象的动态类型相似的类型(如4.4中所定义)
- 与对象的动态类型对应的有符号或无符号类型
- 对应于动态类型的cv限定版本的有符号或无符号类型 对象,
- 聚合或联合类型,包括其元素中的上述类型之一或非 静态数据成员(包括递归地,子集合的元素或非静态数据成员) 或包含联盟),
- 一种类型,是对象动态类型的(可能是cv限定的)基类类型,
- char或unsigned char类型。
你的例子不是上述情况。
答案 1 :(得分:4)
由于A<double>
和A<const double>
是不相关的类型,它实际上是未指定的(最初我认为是未定义的)行为,相应地是,它在现实生活中使用是个坏主意:你永远不知道你可能移植到哪个系统或编译器,改变行为是奇怪的方式。
参考:
5.2.10 / 11:
类型T1的左值表达式可以强制转换为“引用”类型 T2“如果可以明确表达类型为”T1的指针“ 使用reinterpret_cast转换为“指向T2的指针”类型。那 是,参考演员reinterpret_cast(x)具有相同的效果 转换* reinterpret_cast(&amp; x)与内置&amp; x和* 运算符(类似于reinterpret_cast(x))。
所以他们已将我们重定向到前面的5.2.10 / 7节:
可以将对象指针显式转换为对象指针 不同的类型。 ......转换类型的prvalue “指向T1的指针”到“指向T2的指针”(其中T1和T2为 对象类型以及T2的对齐要求为否 比T1更严格,并回到原来的类型产生 原始指针值。任何其他此类指针的结果 转换未指定。
如果f
和g
是适用于容器的算法,那么简单的解决方案就是将它们更改为适用于范围(迭代器对)的模板算法。