【问题标题】:Program should fail/crash while dynamic_cast is working在 dynamic_cast 工作时程序应该失败/崩溃
【发布时间】:2018-03-24 00:01:54
【问题描述】:

在我看来,以下程序应该崩溃,但它不仅可以工作而且显示正确的结果(“derv is called”)。

#include <iostream>
using namespace std;
class base 
{
 public:
  virtual ~base(){}
};
class derv: public base 
{
 public:
   void f() { cout << "derv is called" <<endl;}
};
int main() {
  base* p = new base();
  derv *d1 = dynamic_cast<derv*>(p);

 // Since p point to base , so d1 should return nullptr 
 //calling any function using d1, should fail/crash 
 //but why the following line is working ?? 

 d1->f();
}

抱歉,我忘记在上一篇文章中添加几行:如果我添加单个数据成员并尝试访问它,则会出现分段错误,我认为这是正确的行为。我的问题是为什么访问数据成员会改变行为?当变量未被访问时,调用“f()”函数成功,而同一个函数“f()”在使用数据成员访问时会出现分段错误?是未定义的行为吗?

class derv: public base 
{
 public:
  int x = 0 ; // Added new member,  c++11
  void f() { cout << "derv is called " << x << endl;} //access it here
};

【问题讨论】:

  • 你怎么知道d1 为空?您不检查它,并且您的函数不以任何方式使用this 指针,因此即使它为空,它也有可能不会崩溃。 ideone.com/K2dTD7 这是一个崩溃:ideone.com/US5s6r
  • 这是未定义的行为。
  • 再一次,未定义的行为意味着任何事情都可能发生——包括看起来“有效”。
  • C++ 中没有“应该崩溃”。如果您谈论的是具有特定标志、特定操作系统或特定内存情况的 C++ 编译器的特定实现,那么“应该崩溃”可能是有意义的。但是语言规范中没有强制崩溃。
  • 许多重复项 - hereherehere

标签: c++


【解决方案1】:

取消引用d1 这是一个未定义的程序行为,它是一个空指针:

base* p = new base();
derv *d1 = nullptr;
d1 = dynamic_cast<derv*>(p);

if(nullptr == d1) // condition succeeds which means d1 is nullptr
    cout << "nullptr" << endl; 

安全编程是程序员的任务,而不是编译器的任务,所以一个好的程序在使用前会进行检查:

// avoiding error prones and UBs
if(nullptr != d1)
    d1->f();

【讨论】:

  • 在实践中,您的第二个示例要么推迟未定义的行为,要么将其换成指定但不受欢迎的行为。意外的空指针是一个错误,所以应该使用assert(d1 != nullptr);
  • 你的意思是我应该使用:if(nullptr != d1) d1-&gt;f();?
  • 好吧,我想说if (d1) 在 C++ 中已经是惯用的了。尝试if (d1 != nullptr) 更冗长,但我认为它并没有更好。取决于你的强迫症下降的方式。
  • if (derv* d1 = dynamic_cast&lt;derv*&gt;(p)) ... 恕我直言更好 - 将d1 的范围限制为if 测试/语句,如果您养成这样编写动态演员表的习惯,您就不会意外使用nullptrd1
  • @Raindrop7:首先,您应该使用if(d1 != nullptr) 而不是if(nullptr != d1)。后一种形式的相等比较有时在 20 或 30 年前被推荐,当时编译器没有警告意外赋值,但现在它看起来很有趣。至于是和nullptr比较还是直接写if (d1)……嗯,我通常更喜欢前一种形式,因为它更具可读性。
【解决方案2】:

f 不是虚函数。程序在尝试调用f时不必查找虚函数表,所以无论如何都会调用该方法。

如果您尝试检查thisf 内的指针值,它将是nullptr

【讨论】:

  • 只是出于好奇,null 还是垃圾?还是编译器依赖的UB?
  • 如果 dynamic_cast 失败,结果为空。
  • nullptr 挑选一些细节。
  • @RetiredNinja:我认为这是未定义的行为。
  • f 内部检查this 的结果可能取决于您检查它的方式。允许编译器优化if (this) 以与if (true) 做同样的事情,因为没有合法的方法让this 成为空指针值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-16
  • 1970-01-01
相关资源
最近更新 更多