为什么不使用空自动PTR不会终止程序?

Why doesn't using a NULL autoPtr terminate the program?

本文关键字:终止程序 PTR 为什么不      更新时间:2023-10-16
#include<iostream>
using namespace std;
template<class T>
class autoPtr
{
   public:
    autoPtr(T* ptr)
    {
        cout<<"autoPtr ctr"<<endl;
        loc=ptr;
    }
    autoPtr()
    {
        loc=NULL;
        cout<<"autoPtr dflt ctr"<<endl;
    }
    ~autoPtr()
    {
        cout<<"autoPtr dtr"<<endl;
        delete loc;
    }
    //assignment operator
    autoPtr& operator=(autoPtr& rRef)
    {
        cout<<"autoPtr assignment operator"<<endl;
        loc=rRef.loc;
        rRef.loc=NULL;
        return *this;
    }
    T* operator->()
    {
        cout<<"address -"<<loc<<endl;
        return loc;
    }
private:
    T* loc;
};
  class base
  {
    public:
    base()
    {
        cout<<"base ctr"<<endl;
    }
    ~base()
    {
        cout<<"base dtr"<<endl;
    }
    void printHello(int i)
    {
        cout<<"HELLO : "<<i<<endl;
    }
  };
 int main()
 {
  autoPtr<base> ptr(new base());
  autoPtr<base> ptr1;
  ptr1=ptr;
  ptr1->printHello(1);
  ptr->printHello(2);  //should make the program terminate, but not so ?
 }  

问题是:

ptr->printHello(2);

应该使程序终止,但它没有。为什么不呢?

因为你很幸运。您的程序会导致未定义的行为

ptr1 = ptr

此代码为第一个auto_ptr对象ptr分配NULL地址,为第二个对象ptr1分配一些非NULL地址。源对象在分配期间丢失引用(=(。

执行语句时:

ptr->printHello(2);  

ptrNULL指针,取消引用NULL指针是未定义的行为

但是由于在函数printHello()中,您不访问任何类成员变量,所以它可以正常工作。在类中添加一个成员变量,然后尝试在printHello()函数中访问该变量,您将看到它(很可能(崩溃

需要注意的是,未定义的行为意味着任何事情都可能发生,并且行为不能根据C++标准中的语言规范进行定义。在这种情况下,它有效的事实并不能保证它总是有效的,而且它仍然是一种未定义的行为。

ptr->printHello(2);//should make the program terminate.but not so...y ??

不一定。它实际上是未定义的行为。如果幸运的话,你的程序会崩溃。

未定义的行为不能保证任何定义的行为。所以你不知道在执行上面的行时会发生什么。

你犯了一个BIG错误,你越早纠正它,你的C++生活就会越好。这个错误将崩溃与错误混为一谈。

取消引用NULL指针是"未定义的行为"。这并不意味着你会得到一个运行时错误。这并不意味着你的程序会崩溃。这并不意味着会发生任何有用的事情。这并不意味着你所希望的一切都会发生。

这意味着任何事情都可能发生。

什么都不包括。

事实上,"一无所有"是一种非常常见的情况,也是一种非常危险的情况。即使存在未定义的行为错误,程序也会保持正常工作。

当然,直到大的演示日,他们会撞到你的脸上,让你的节目变得悲惨和美好,只为嘲笑它。

你会开始指责操作系统、编译器、硬件、"运气不好"等等。

未定义的行为,加上C++的复杂性,有时还有不合逻辑的规则和选择,使语言变得非常危险,不可能通过实验来学习。认真思考你写的每一行C++。语言中无法言喻的假设是,你永远不会犯那种错误。

C++中没有"运行时错误天使"。只是"未定义的行为守护程序"。

PS:您的实现不处理复制构造函数。

所有指出使用NULL指针是未定义行为而不是保证崩溃的人当然都是100%正确的。

然而,在这种情况下,有一些非常具体的东西使这里的结果不太可能是崩溃:也就是说,您调用的printhello()方法是而不是虚拟函数。这意味着进行调用的代码实际上不需要知道对象地址:它是(或者至少可以是,我相信通常是(链接的&调用的方式与简单的全局函数几乎相同。

对象地址当然是计算出来的,并作为隐藏的this参数传递给函数(因为它不是静态函数(,但这并不意味着不能调用该函数。我认为如果你在printhello()中打印出this,你会看到它打印出0,但这并不意味着你的程序会崩溃。

当然,正如其他人所指出的,只要您引用任何成员变量或调用任何虚拟方法,就很可能崩溃(因为在这种情况下,您使用this作为指向对象的指针,而对象已不再是对象(一个重要的演示也可能会增加崩溃的可能性!(。