【问题标题】:Is this c++ code containing reinterpret_cast between templated types well-defined?这个包含模板类型之间的 reinterpret_cast 的 c++ 代码是否定义明确?
【发布时间】:2021-08-25 13:41:14
【问题描述】:

https://onlinegdb.com/RU3bYEfCB

#include <iostream>
using namespace std;

//--------------------Foo------------------
template<int Index>
class Foo {
 public:
  Foo(string first, string second, string third) {
    foo_[0] = first;
    foo_[1] = second;
    foo_[2] = third;
  }

  string operator()() const {
    return foo_[Index];
  }

 private:
  string foo_[3];
};

//---------------------Bar------------------
class BarBase {
 public:
  virtual string operator()() const { return "BarBase"; };
};

template<int Index>
class Bar : public BarBase {
 public:
  Bar(string first, string second, string third) {
    bar_[0] = first;
    bar_[1] = second;
    bar_[2] = third;
  }

  string operator()() const {
    return bar_[Index];
  }

 private:
  string bar_[3];
};

//---------------------Wrapper------------------
class WrapperBase {
 public:
  virtual string operator()() const { return "WrapperBase"; };
};

template<typename T>
class Wrapper : public WrapperBase {
 public:
  Wrapper(T* functor) : functor_(functor) {}
  
  string operator()() const {
    return (*functor_)();
  }
 
 private:
  T* functor_;
};

int main()
{
    Foo<0> foo0("A", "B", "C");
    Foo<1>& foo1 = *reinterpret_cast<Foo<1>*>(&foo0);
    Foo<2>& foo2 = *reinterpret_cast<Foo<2>*>(&foo0);
    cout<< "foo: " << foo1() << foo2() <<"\n";
    
    Bar<0> bar0("A", "B", "C");
    Bar<1>& bar1 = *reinterpret_cast<Bar<1>*>(&bar0);
    Bar<2>& bar2 = *reinterpret_cast<Bar<2>*>(&bar0);
    cout<< "bar: " << bar1() << bar2() <<"\n";
    
    WrapperBase* wrappedfoo0 = new Wrapper<Foo<0>>(&foo0);
    WrapperBase* wrappedfoo1 = new Wrapper<Foo<1>>(&foo1);
    WrapperBase* wrappedfoo2 = new Wrapper<Foo<2>>(&foo2);
    cout<< "wrapped foo: " << (*wrappedfoo1)() << (*wrappedfoo2)() <<"\n";

    return 0;
}

输出:

foo: BC
bar: AA
wrapped foo: BC

Foo 和 Bar 完全等价,唯一的区别是 Bar 继承自基类,实现的操作符是虚的,所以 Bar 有一个虚函数指针,而 Foo 没有。

我想我明白为什么 bar 打印 AA 而 foo 打印 BC (如果我错了,请纠正我)。 这两个类都实例化了 3 次,每个 operator() 有三个实现,各自的索引是硬编码的。但是,由于 Bar 有一个虚函数指针,在 reinterpret_casting 从 Bar 到 Bar 之后,虚函数指针仍然指向 Bar

的实现

我想知道这段代码是否定义良好,尤其是在“Foo”和“Wrapped Foo”的情况下。因此,只要我的仿函数中没有继承,我就可以将它重新解释为另一个 Foo 并且在调用 operator() 时它将使用当前变量的模板类型的索引(分别是模板类型)调用它包装器被实例化了)?

//编辑: 如果 Foo 构造函数被移除(而 foo_ 成员改为公开并从外部初始化),它会是什么样子?

那么它应该构成一个 POD 并且标准 (9.2.18) 说 reinterpret_cast 和 POD:

指向 POD 结构对象的指针,使用 reinterpret_cast,指向它的初始成员(或者如果该成员是 位域,然后到它所在的单元),反之亦然。 [ 注意:因此在 POD 结构中可能存在未命名的填充 对象,但不是在开始时,因为有必要实现适当的 对齐。

那么,如果 Foo 构造函数被移除,那么 Foo(和包装的 foo)的行为是否定义良好?

【问题讨论】:

  • reinterpret_cast 的大多数用法都会导致 UB,包括这个。
  • Foo&lt;T&gt; 是与Foo&lt;U&gt; 完全不同的类型。这个问题基本上归结为将long long* 重新解释为double* 是否安全,不,它是UB。
  • 注意:F&lt;0&gt;F&lt;1&gt;F&lt;2&gt; 是不相关的类。

标签: c++ inheritance virtual-functions reinterpret-cast


【解决方案1】:

Foo 的所有可能实例均不相关,并且也与Bar 的所有可能实例无关,它们也彼此无关。

在不相关类型之间使用reintepret_cast 的行为是未定义

看起来相同并不重要。例如,考虑

struct A{}; struct B{};

A a;

reinterpret_cast&lt;B&amp;&gt;(a) 的行为也未定义。

【讨论】:

  • @Caleth:我就是这个意思,老实说 ;-)
  • 谢谢,如果 Foo 构造函数被删除,它会是什么样子?在这种情况下,它应该构成 POD 类型的定义,并且由于所有 POD 类型具有相同的数据布局,因此行为应该是明确定义的,不是吗?
猜你喜欢
  • 2011-08-26
  • 1970-01-01
  • 2014-02-07
  • 2020-03-15
  • 2019-12-14
  • 2012-09-27
  • 1970-01-01
  • 1970-01-01
  • 2011-06-10
相关资源
最近更新 更多