Menu

#859 Incompatibility between any operator Delete[] (or the only overload operator Delete) and polymorphism

closed
nobody
None
compiler
2018-09-21
2017-07-09
No

I just added this note in documentation
Any operator Delete[] (or the only overload operator Delete) is not compatible with the polymorphism, even using virtual destructor that may in addition induce crashing.
Instead of being obliged to call any operator Delete[] (or the only overload operator Delete) on a child-type pointer, the safest is to simply call (on the base-type pointer) a user virtual member procedure that launches any operator Delete[] (or the only overload operator Delete) automatically at child-level.

Looking at C++ standard (ISO/IEC 14882:2003(E)), §12.5-7:
https://www.google.fr/url?sa=t&rct=j&q=&esrc=s&source=web&cd=2&ved=0ahUKEwiV8fTT35nRAhVH1hQKHX6sA9MQFgglMAE&url=http%3A%2F%2Fwww.open-std.org%2Fjtc1%2Fsc22%2Fwg21%2Fdocs%2Fpapers%2F2013%2Fn3690.pdf&usg=AFQjCNG6DidKwqW19sOTGQBb71zbqx9P_w&bvm=bv.142059868,d.d2s&cad=rja
it seems that there is a similar problem in C++ language.

For more information and test codes, see at forum:
https://www.freebasic.net/forum/viewtopic.php?f=3&t=25286

Discussion

  • fxm (freebasic.net)

    As the overload DELETE([]) operators are static, maybe it's an unsolvable problem (for calling the well-level operator), unless of adding specific compiler code (like hidden virtual procedures at each possible inheritance level) for calling at run-time the DELETE operator of well-level.

    Look at C++ standard (ISO/IEC 14882:2003(E)), also at §5.3.5-3:
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf

     

    Last edit: fxm (freebasic.net) 2018-08-15
    • Jeff Marshall

      Jeff Marshall - 2018-08-24

      fxm, thanks for pointing me to all the information. Very helpful.

      Short answer:
      As you suspect, unsolvable. There's a number of behaviours here that simply do not work together in certain scenarios. Even if we did make it safer in some way, it's still going to be exposed as an unsafe pointer type.

      • static overloaded new/delete/new[]/delete[] is for memory allocation & deallocation only, the object doesn't exist,
      • compare implicit new/delete, calls to malloc()/free(). free() does not care if it is the base or derived type pointer, it is same memory address.
      • new[] returns a pointer type, and as a pointer type, we should expect that pointer math will work, except,
      • main problem is when sizeof(basetype) <> sizeof(derivedtype), pointer math is wrong.
      • but, should be safe with polymorphic interfaces, that is, all data is in the base type only.

      Longer answer:

      implicit operator new/delete:
      - these just call malloc()/free().
      - free() doesn't care if it is pointer to the base type or a pointer to the derived type, it works same.

      static overloaded operator new/delete/new[]/delete[]:
      - these are to replace/override memory allocating/deallocating functions. It's just memory at this point, the object doesn't exist here.
      - Maybe a use is for a set of derived types to all call the same memory allocator/deallocator through these overloads
      - Only time I ever overload these is for memory tracking

      using new/delete:
      - allocate/deallocate memory and call the constructor/destructor, easy.

      using new[]/delete[]:
      - one allocate/deallocate for many objects and call all the constructors/destructors, not always safe though, depending on usage.
      - all objects together in memory and returns a pointer, so we should expect pointer math to work

      Here's the big problem, when sizeof(parent)<>sizeof(child):

      type parent extends object
          dim i as integer
          declare constructor()
          declare virtual destructor()
      end type
      
      type child extends parent
          dim j as integer
          declare constructor()
          declare destructor()
      end type
      
      '' because we are allocating one size of type to another size of type
      dim p as parent ptr = new child[10]
      
      '' this is unsafe, pointer math is wrong, to call destructors
      delete[] p 
      

      So then, why is new[]/delete[] allowed with derived types? Well, as far as I can tell, it's safe with polymorphic interfaces. That is, derived types that add member procedures only, and do not add data members.

      type Generic_Blob extends object
          dim i as integer
          declare constructor()
          declare virtual destructor()
      end type
      
      type Specific_Interface extends Generic_Blob
          declare constructor()
          declare destructor()
          '' ... procs
      end type
      
      dim p as Generic_Blob ptr = new Specific_Interface[10]
      delete[] p  '' safe 
      
       
  • Jeff Marshall

    Jeff Marshall - 2018-09-21
    • status: open --> closed
     
  • Jeff Marshall

    Jeff Marshall - 2018-09-21

    I believe this bug has been addressed in the documentation. Thanks, fxm.

     

Log in to post a comment.