为什么不使用NULL autoPtr终止程序?

时间:2011-08-09 07:32:54

标签: c++

#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);

应该使程序终止,但事实并非如此。为什么不?

4 个答案:

答案 0 :(得分:8)

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

ptr1 = ptr

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

执行声明时:

ptr->printHello(2);  

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

但是因为在函数printHello()内你没有访问任何类成员变量,所以它工作正常。向您的班级添加成员变量,然后尝试在printHello()函数中访问该变量,您会看到它(很可能)崩溃

重要的是要注意未定义的行为意味着可能发生任何事情,并且无法根据C ++标准中的语言规范来定义行为。在这种情况下,它起作用的事实并不能保证它始终存在并且它仍然是未定义的行为。

答案 1 :(得分:4)

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

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

未定义的行为不保证任何定义的行为。因此,您不知道执行上述行时可能会发生什么。

答案 2 :(得分:3)

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

取消引用NULL指针是“未定义的行为”。这并不意味着您将收到运行时错误。这并不意味着你的程序会崩溃。这并不意味着任何有用的事情都会发生。这并不意味着你可能会发生任何事情。

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

不包括任何内容。

实际上“没有”是一个非常常见的案例,也是一个非常危险的案例。即使存在未定义的行为错误,程序仍然可以正常工作。

直到当然是大型演示日,当他们在你的脸上崩溃时,你的表演会让你的表演变得悲惨,而且只是为了嘲笑它。

你会开始责怪操作系统,编译器,硬件,“运气不好”等等。

未定义的行为,加上C ++复杂性以及有时不合逻辑的规则和选择,使得语言非常危险,无法通过实验学习。 仔细思考你编写的每个C ++行。无法言喻的语言是你永远不会犯这样的错误。

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

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

答案 3 :(得分:1)

每个人都指出使用NULL指针是Undefined Behavior而不是保证崩溃当然是100%正确。

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

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

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