Deleting Pointers



  • On 04/11/2016 at 10:03, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   13 
    Platform:   Windows  ;   
    Language(s) :     C++  ;

    ---------
    Hi,
    Some of the C4D based pointers don't seem to be deletable by normal means.
    Up to this point I've just let that go. Because null pointers don't take up much space. And I guess they get deleted when C4D closes.
    But it seems technically wrong to me that there's no way to delete them. And it seems like a bad practice to leave them behind. Even though everyone seems to be doing it as a normal part of writing C4D plugins.

    What mostly concerns me is creating hundreds, or thousands of these null pointers. And leaving them there for the entire time that C4D session is open.
    If I wanted to. Is there some way to to delete them (BaseMaterial, BaseObject, PolygonObject, etc...)?

        //Standard C++ code that deletes an empty pointer  
      //Removes everything as expected  
      int *myptr = nullptr;  
      delete myptr;  //<---This is standard C++ and it works  
      
      //Deleting a C4D based array   
      //Removes everything as expected  
      GeDynamicArray<String>myarray(10);  
      myarray[0] = "hello";  
      myarray.FreeArray();  
      //Can't do the this because the array has not only been freed. But also myarray was deleted  
      //myarray[0] = "world";  
      //GePrint(myarray[0]);  
      
      //This is where it gets strange. There does not seem to be a way to delete some of the C4D based pointers  
      //How do we delete a C4D based empty pointer like this?  
      BaseObject *obj = nullptr;  
      //delete obj;  //<---Not Allowed!!  
      BaseObject::Free(obj); //<--Nope. Frees memory. But does not delete the actual pointer  
      if(obj == nullptr) GePrint("obj is Null. But it still exists!");
    

    -ScottA



  • On 04/11/2016 at 13:17, xxxxxxxx wrote:

    Hi ScottA,

    I am not really sure what you mean.

      
      
    int *myptr = nullptr;   //nothing to delete here. the pointer it self occupiers 8 bytes.  
    delete myptr;  // will actually do nothing !     
      
    {  
       BaseObject *obj = nullptr;  //nothing to delete here. the pointer it self occupiers 8 bytes.  
    } //the pointer it self will be deleted on out of scope.  
      
    


  • On 04/11/2016 at 14:16, xxxxxxxx wrote:

    Hi Remo,

    I'm basically concerned about the pointers staying in memory and not being completely deleted.
    I'm concerned about those 8 bits piling up if I create a lot of them.
    I was concerned about stack overflows. They do sit of the stack (not the heap) right?

    I didn't know that they got deleted when out of scope.
    If they do get deleted when out of scope. Then the way I'm checking them is wrong.
    I've been checking them in the same scope. And that's not going to work. DOH! 😉

    I'm my Melange app. I don't have an undo stack.
    So I'm copying all of the objects in the scene into an array of BaseObject pointers.
    Then copying them a second time to another array so if the user wants to get back the original object, they can use the one in that array.
    That can end up being a lot of pointers in a scene with hundreds of objects. So I'm a little bit nervous about all those pointers being created.
    There are things I can use to free and delete the arrays the pointers are in.
    And I can use Free on the pointers to delete anything they are holding.
    But there's nothing I see where I can manually delete the null pointers themselves. I'm relying on C4D to do that. And that makes me a bit nervous. Especially in Melange where C4D isn't even open.

    Thanks for the help,
    -ScottA



  • On 04/11/2016 at 15:09, xxxxxxxx wrote:

    Hi ScottA,

    Well may be I was not precise enough.

      
    void **SomeFunction** ()   
    {  
      int *myptr = nullptr;  // pointer to nothing, it is 8 bytes on 64-bit system. It is on **stack**.   
    }   
    // **stack for this function will be freed on function exit.  
      
    ** void **SomeWrongFunction** ()   
    {  
      maxon::BaseArray<Int*> ptrArray;  /// array with pointers on the **heap.  
      **ptrArray **.** Append(new Int);  
    }   
    // the ptrArray will be deleted on scope exit.  
    // But int allocated with **new will be leaked !!!  
      
    **  
    void **SomeWrongFunctionToo** ()   
    {  
      int ptrArray[1000000];  /// huge array on the **stack,** this may lead to ******stack overflow**!!!  
    }  
      
      
    void SomeBetterFunction()   
    {  
      maxon::BaseArray<std::unique_ptr<Int>> ptrArray;  /// array with pointers on the heap.  
      ptrArray.Append(new Int);  
    }    
    // the ptrArray and memory allocated with **new** will be deleted on scope exit.  
    

    In short do not use raw new and delete manually.
    Always use smart pointers like std::unique_ptr or C4D own AutoFree and Co.

    regard,
    Remo



  • On 04/11/2016 at 15:26, xxxxxxxx wrote:

    Ok. Thanks.
    For the record. I'm not using new or any standard C++ code. I just used it as an example.
    I'm using either Alloc or grabbing them with an iterator to fill all of the pointers. But with Melange there's a good chance that I might eventually want to use non C4D SDK pointers some day.

    As long as the pointers do get automatically deleted based on scope. I think I'm safe.
    I haven't tried AutoAlloc yet with Melange either. I don't even know if it's supported. They aren't used in the examples.

    -ScottA



  • On 05/11/2016 at 10:46, xxxxxxxx wrote:

    No mater if this is new or any other memory allocation like BaseObject::Alloc() do not do this manually.
    Because this way it is all too easy to leak memory or other resources.

    This is C++ and NOT C and RAII  is the solution for resource management.
    So if you call BaseObject::Free  manually then this is already wrong and dangerous.
    If you free any resource manually then you probably already have a resource leak or will have it at some time.

    Smart pointers is RAII solution for memory (is a resource too) but there are other resources like files and threading locks...

    Remo



  • On 05/11/2016 at 11:44, xxxxxxxx wrote:

    Using Melange. I think I'm forced to use Alloc and manage the memory manually.
    I'm not seeing Auto anything it. But I could be missing it.

    -ScottA



  • On 07/11/2016 at 03:14, xxxxxxxx wrote:

    Hi Scott,

    you are not mistaken, the AutoAlloc (AutoFree, AutoMem...) functions are not available in the Melange SDK.

    But perhaps you should take a step back.
    Your questions and confusion have nothing to do with the Melange SDK (or any of the other MAXON SDKs).
    Forget about AutoAlloc and unique pointers for a moment and try to look into the underlying basics. I'd really suggest to follow some of the links I provided in the "Create and insert material" thread and then use a search engine of your liking to dive a bit deeper into these topics. If the concepts of scope, local variable, heap and stack/call stack don't mean anything to you, it will be tedious (if not impossible) to discuss memory allocation, memory leaks or different pointer types.
    For example are you aware, that your machine sees no difference between the following three variable definitions (on a modern 64-Bit machine)?

        UInt64 myUInt;
        void* myPtr;
        BaseObject* myOp;
    

    It really does not. Only the compiler applies some different rules, when working with these.

    Lastly, I don't think, this is the right forum to learn/teach about programming basics. Sites as StackOverflow are probably way better suited for this and basically all answers to your questions have been discussed there already. Please, don't get me wrong, I really like to discuss with you, but these forums are dedicated to MAXON's SDKs and we are supposed to provide support for these, not for general programming or C++ questions.

    Having said that, please go on in this thread to discuss these matters with the community, but please, don't expect the SDK Team to contribute. We will most likely do, if we see misinformation, but otherwise (and I really hope you don't mind) we are lacking the time to get into such topics.



  • On 07/11/2016 at 07:21, xxxxxxxx wrote:

    Hi Andreas,
    My only source of confusion was if there was another step beyond Freeing a pointer in the C4D SDK. Because in raw C++ there are ways to delete the pointer after it has been nulled. But in the SDK there doesn't appear to be. That's where I wanted some clarification.
    Thanks to Remo. I now know that they get automatically deleted based on scope.

    -ScottA



  • On 07/11/2016 at 09:34, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    Because in raw C++ there are ways to delete the pointer after it has been nulled.

    It may be your wording, but this statement doesn't make any sense (to me). Would you show an example of what you mean?

    It's important to understand that it's not the pointer you usually delete, but the memory that the pointer is pointing to.

    Cheers,
    Niklas



  • On 07/11/2016 at 10:05, xxxxxxxx wrote:

    Sure Niklas.
    Here's an example from my notes.
    I don't know where I picked up this code. But it must have been from either a tutorial or a Stack Overflow post:

    int x = 10;  
    int *ptr = &x;  
      
    //Manually delete the pointer  
    //Probably not necessary. But the compiler will let me do it.  
    delete ptr;    
    

    The compiler won't let me delete an C4D SDK *pointer this way. Even after I use Free on it.

    -ScottA

    *Edit:
    There is also gDelete(classPointer) in the C4D SDK. Which also made me wonder if I was also supposed to be manually deleting my *BaseObject, *BaseMaterial, etc. pointers.
    But I'm guessing what gDelete() does is more akin to Free. Rather than delete.



  • On 07/11/2016 at 15:44, xxxxxxxx wrote:

    It doesn't clarify on the "after is has been nulled" part, actually that was the one which was most likely
    making me think you might have a misconception in that regard.

    Anyway, regarding the snippet above, it is not just not necessary, it is actually invalid/illegal to delete  the
    pointer in that case, because it is not pointing to memory that you have previously allocated on the heap.

    The reason why the compiler will not let you delete  pointers to BaseObject or the like is because the
    destructors are (intentionally) marked as private. Also, you must only use delete on a pointer when you
    know that it the memory it points to  has been allocated with new.

    Same as with the destructor, the constructors of BaseObject etc. are also marked as private, that is why
    you can not create an instance of these classes with new  or on the heap  *stack.

    gDelete() was available in the R15 SDK and earlier as a counterpart to gNew() which where both basically
    the same as delete  and new  (respectively) but they are using the Cinema 4D's own memory management.

    Now the reason why the constructors and destructors of many of Cinema 4D's classes are marked private
    and instead have Alloc() and Free() static functions is because of the way the C4D SDK is structured.
    As you probably already know, all of the code of all the member functions in these classes is actually
    implemented in Cinema 4D itself. There's a big structure in the C4D SDK that contains pointers to the
    actual implementation of these methods and in the C4D SDK you can see that the methods that you
    actually call just forward to these function pointers.

    Bool BaseContainer::operator == (const BaseContainer& c) const
    {
    	return C4DOS.Bc->Compare(*this, c);
    }
    

    Best,
    -Niklas



  • On 07/11/2016 at 16:49, xxxxxxxx wrote:

    Ok.
    Thanks for the information Niklas.

    -ScottA



  • On 20/11/2016 at 06:30, xxxxxxxx wrote:

    Using Melange. I think I'm forced to use Alloc and manage the memory manually.
    No you are not forced to manage the memory manually !

    May be you can read about std::unique_ptr for example here:
    http://shaharmike.com/cpp/unique-ptr/

    The behavior of AutoFree and Co. are mostly the same.

    regards,
    Remo



  • On 20/11/2016 at 07:31, xxxxxxxx wrote:

    I meant that I'm forced to handle them manually if I stick with using the SDK.

    With Melange we end up in a sort of a bizzaro world of C4D development.
    We get told repeatedly here by support not to use standard C++ stuff in our plugins. And that makes sense 99% of the time.
    But using Melange it's all about making programs in outside applications. Instead of plugins hosted inside C4D. Which require using all of those bad things we are told not to use.
    So we can't follow that rule of not using standard C++ stuff anymore.
    But on the other hand. We do still need to follow the Melange SDK practices. So it becomes a challenging game of figuring out the best way to combine both things.
    A tug of war.

    When using the Melange SDK. I kinda feel like a child of divorced parents(Standard & SDK).
    I have to visit each one. But each one tells me not to use the other.

    -ScottA



  • On 21/11/2016 at 08:43, xxxxxxxx wrote:

    Well, I find this perfectly reasonable and not very bizarro at all.
    After all the C4D and the Melange SDK have two completely different purposes.

    A plugin obviously has to live inside of the Cinema 4D application and thus its application binary interface has to match and it should make use of the services provided by Cinema 4D.

    Melange on the other hand is made to be used in other/stand-alone applications. So it doesn't come with its own memory management, but instead you use the one most suitable there. You can even tell Melange not to use "standard" memory management for its own allocations, but instead to use a custom memory management provided by the application it is used in.



  • On 21/11/2016 at 09:36, xxxxxxxx wrote:

    Yes. But there are rules to this. And I don't have anyone looking over my shoulder warning me if I do something wrong.
    And since we are constantly told not to use standard C++ here. Rather than told how to properly mix standard C++ with the SDK's. When we use Melange we are basically on our own.

    When I'm using Melange. I'm constantly wondering if I'm breaking some rule.
    When I'm left on my own. I can invent some very cool things that should probably never be done. 😂

    I'm really excited about using Qt and Melange together. It's really fun to take full advantage of Qt's wonderful gui stuff, and also be able to target things for c4d.
    I've written a couple of apps so far. But I think I've only begun to tap the potential there.
    But it's also kinda scary without knowing much about the rules.
    I hope Maxon keeps pushing Melange further. It's really been great fun using it with Qt.

    -ScottA



  • On 21/11/2016 at 09:54, xxxxxxxx wrote:

    TL;DR the reason we are supposed not to use the standard
    library is because Cinema does not use exception handling and
    the majority of the C++ STL uses exceptions. You can use
    exceptions in your plugins, but any exception reaching the
    Cinema 4D loop will crash the app.

    In Melange, you're in your own environment and you are free to
    use exceptions if you want to. Since no call in the Melange SDK
    gets "out of your scope" you could for example (not a good 
    practice though) simply put a bug  big try-catch block in your main()
    function.

    Best,
    -Niklas

    PS: Oh and BaseArray and HashMap are usually pretty fast
    compared to vector and unordered_map. Some time ago there
    was a thread with benchmarks of them compared to various
    implementations of the STL containers.


Log in to reply