将指针转换为指针引用是否会导致未定义行为?

4

我遇到了下面这段丑陋的代码,想知道标准是否对此有规定。调用foo()函数是否被认为是导致未定义行为?还是无害的?

#include <iostream>

class Base {};
class Derived : public Base {};

void foo(Base *&b)
{
  std::cout << "foo" << std::endl;
}

int main()
{
  Derived *der = new Derived();

  foo((Base *&)der);

  return 0;
}

我认为使用丑陋的C风格强制类型转换是因为简单的 (Base *) 转换会导致编译错误。即使现在它能够编译,是否只是因为严格别名规则?或者引用类型的强制类型转换符合标准吗?


3
是的,这是一个"strict aliasing violation"(严格别名违规)的问题。 - M.M
1
@M.M,你能详细解释一下吗? - lubgr
@M.M 我也同意lubgr的观点。如果您能提供一些参考来源或解释您的评论,那将不胜感激。 - theroyn
一个关于严格别名的参考资料。 - Sander De Dycker
1
想象一下,如果Derived有多个基类,并且您将其转换为不位于对象开头的基类,会发生什么。 - sklott
1个回答

1
这是相当UB的,因为实际上你正在将派生指针重新解释为基类指针。原因是你没有将Derived指针转换为Base指针,而是将T&转换为U& - 虽然T和U具有相同的大小和对齐方式(都是对象指针类型),但它们无法进行static_cast转换。这反过来要求C风格的转换行为像reinterpret_cast。
虽然在你的情况下它通常(tm)会有效果(基类子对象位于派生对象的索引0处),但在使用多个或虚拟继承时预计会(tm)失败。
可以通过执行以下操作轻松达到预期效果:
Derived* der = new Derived();
Base* base = der; // conversion to base
foo(base);
der = static_cast<Derived*>(base); // assumes that whatever base points to now is also (derived from) Derived

请注意,在类型转换中使用引用通常并不成问题。例如:
Derived derived;
Base& base = static_cast<Base&>(derived); // equivalent to *static_cast<Base*>(&derived)

2
挑剔一点:不同的指针类型不能保证具有相同的大小(或对齐方式)。对于实际实现来说,这是一个合理的假设,特别是在谈论指向派生类和基类的指针时。 - Sander De Dycker
@SanderDeDycker 这个问题表明,由于无效的转换,编译器没有拒绝这种形式的程序(是的,我太懒了,不想查看是否需要该诊断)。 - danielschemmel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接