delete a NULL pointer does not call overloaded delete when destructor is written

前端 未结 7 2041
慢半拍i
慢半拍i 2021-02-02 15:05
class Widget
{
    public:
        Widget() {
            cout<<\"~Widget()\"<

        
相关标签:
7条回答
  • 2021-02-02 15:09

    First of all, this can really be simplified down to delete (Widget*)0 - everything else in your main() is unnecessary to repro this.

    It's a code generation artefact that happens because 1) user-defined operator delete must be able to handle NULL values, and 2) compiler tries to generate the most optimal code possible.

    First let's consider the case when no user-defined destructor is involved. If that's the case, there's no code to run on the instance, except for operator delete. There's no point in checking for null before transferring control to operator delete, because the latter should do a check anyway; and so the compiler just generates unconditional call of operator delete (and you see the latter print a message).

    Now the second case - destructor was defined. This means that your delete statement actually expands into two calls - destructor, and operator delete. But destructor cannot be safely called on a null pointer, because it could try to access class fields (the compiler could figure out that your particular destructor doesn't really do it and so is safe to call with null this, but looks like they don't bother in practice). So it inserts a null check in there before the destructor call. And once the check is already there, it might as well use it skip the call to operator delete, too - after all it's required to be a no-op anyway, and it will spare an extra meaningless check for null inside operator delete itself in case the pointer actually is null.

    So far as I can see, nothing in this is in any way guaranteed by ISO C++ spec. It's just that both compilers do the same optimization here.

    0 讨论(0)
  • 2021-02-02 15:14

    I don't have a good answer, but I have simplified the issue slightly. The following code removes the operator new and exception handling:

    #include <iostream>
    using namespace std;
    
    class Widget {
    
      public:
        Widget() {
            cout<<"Widget()"<<endl;
        }
        ~Widget() {
            cout<<"~Widget()"<<endl;
        }
    
      void operator delete(void *v) {
           cout << "operator delete" << endl;
      }
    };
    
    int main() {
        Widget* w = 0;
        cout << "calling delete" << endl;
        delete w;
    }
    

    This still exhibits the same behaviour and des so on both VC++ and g++.

    Of course, deleting a NULL pointer is a no-op, so the compiler does not have to call operator delete. If one actually allocates an object:

        Widget* w = new Widget;
    

    then things work as expected.

    0 讨论(0)
  • 2021-02-02 15:30

    I remember something similar on operator delete a while ago in comp.lang.c++.moderated. I cannot find it now, but the answer stated something like this ..

    Unfortunately, the language specification is not sufficiently clear on whether the control should go into the overloaded 'operator delete' when the delete-expression is invoked on the null-pointer of corresponding type, even though the standard does say that delete-expression on null-pointer is a no-op.

    And James Kanze specifically said:

    It's still the responisiblity of operator delete (or delete[]) to check; the standard doesn't guarantee that it won't be given a null pointer; the standard requires that it be a no-op if given a null pointer. Or that the implementation is allowed to call it. According to the latest draft, "The value of the first argument supplied to a deallocation function may be a null pointer value; if so, and if the deallocation function is one supplied in the standard library, the call has no effect." I'm not quite sure what the implications of that "is one supplied in the standard library" are meant to be---taken literally, since his function is not one provided by the standard library, the sentence wouldn't seem to apply. But somehow, that doesn't make sense

    I remember this becoz i had a similar prob sometime back and had preserved the answer in a .txt file.

    UPDATE-1:

    Oh i found it here. Also read this link defect report. So, the answer is Unspecified. Chapter 5.3.5/7.

    0 讨论(0)
  • 2021-02-02 15:30

    You were trying to delete a NULL pointer. So, the destructor was not getting called.

    class Widget
    {   
    public:        
        Widget()
        {            
            cout<<"Widget()"<<endl;        
        }       
    
        ~Widget() 
        {          
            cout<<"~Widget()"<<endl;    
        }    
    
        void* operator new(size_t sz) throw(bad_alloc) 
        {      
            cout<<"operator new"<<endl;  
            return malloc(sizeof(Widget));
            //throw bad_alloc();    
        }  
    
        void operator delete(void *v)
        {               
            cout<<"operator delete"<<endl;   
        }
    };
    
    int main()
    {
    
        Widget* w = NULL; 
        try 
        {   
            w = new Widget();
            //throw bad_alloc();
        }   
        catch(bad_alloc) 
        {        
            cout<<"Out of Memory"<<endl;  
        }   
        delete w; 
    }
    

    Output:

    operator new
    Widget()
    ~Widget()
    operator delete

    0 讨论(0)
  • 2021-02-02 15:31

    The object destructor is called before the delete operator. So my guess would be that it tries to call the destructor, realizes that the pointer is NULL therefore

    1. doesn't call destructor which needs an instance
    2. stops the deleteing operation there (kind of speed optimization IMHO).

    As Neil said, if w contains a Widget, it should work.

    0 讨论(0)
  • 2021-02-02 15:32

    Would like a leave a comment, instead of answer, didn't have enough privileges being a new member.

    An exception is being raised during the creation of object. The destructor is not getting called, as the object itself is not created.

    That you can also observe, as the messages from the constructor & destructor are not getting displayed.

    But, the delete is being called when the destructor is not defined. If thought in the directon that when destrcutor is not defined, C++ Compiler considers it as any other operator, the compiler by default provides a destructor when not defined.

    0 讨论(0)
提交回复
热议问题