Backward Compatibility Issue



  • On 18/11/2013 at 13:42, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   R9 - R15 
    Platform:   Windows  ; Mac  ;  Mac OSX  ; 
    Language(s) :     C++  ;

    ---------
    Howdy,

    OK, in my attempt to keep my code backward compatible I've created lots of wrapper functions with preprocessor directives that check the API_VERSION and compile accordingly. This has been working beautifully in that I only code once and compile for all versions.

    But with the memory allocation changes in R15, I've run into a small snag.

    Here is my wrapper code for GeAlloc()/GeFree() and NewMemClear()/DeleteMem() :

    template<typename T>
    T* CDAlloc(LONG s)
    {
    #if API_VERSION < 15000
    	LONG size = sizeof(T) * s;
    	return (T* )GeAlloc(size);
    #else
        return (T* )NewMemClear(T,s);
    #endif
    }
      
    template<typename T>
    void CDFree(T* x)
    {
    #if API_VERSION < 15000
        GeFree(x);
    #else
        DeleteMem(x);
    #endif
    }
      
    
    

    ... which seems to work except for an intermittent crash upon calling CDFree().

    Is there something wrong with the above code?

    Adios,
    Cactus Dan



  • On 18/11/2013 at 14:24, xxxxxxxx wrote:

    my "guess" is that "NewMemClear" should be "NewMem" as the first one auto clears and doesn't need delete "but I'm noob so all of this may be wrong"



  • On 18/11/2013 at 14:25, xxxxxxxx wrote:

    for safety , do :
    if (x) DeleteMem(x);



  • On 18/11/2013 at 14:43, xxxxxxxx wrote:

    Howdy,

    Well, I should have specifically mentioned that it is the versions prior to R15 that are crashing, in other words the call to CDFree() wrapped to GeFree().

    In all areas where I'm calling that function, I'm calling it like this:

    if(ptr) CDFree(ptr);
    

    ... which seemed fine when using GeFree() in the prior versions, but the wrapped version seems to cause an intermittent crash.

    Adios,
    Cactus Dan



  • On 18/11/2013 at 15:37, xxxxxxxx wrote:

    well not sure , but may be this is related
    "The other change is that while GeAlloc would return nullptr for size  0NewMem()/NewMemClear() will return a valid address (like malloc)."



  • On 19/11/2013 at 04:01, xxxxxxxx wrote:

    Hi Dan,

    I think you have missed only one &  in  CDFree(T* ptr) it must be CDFree(T*& ptr).
    CDFree() will also not only delete the memory but set ptr to nullptr.

      
        
        
        template<typename T>
        T* CDAlloc(LONG s)
        {
        #if API_VERSION < 15000
        	LONG size = sizeof(T) * s;
        	return (T* )GeAlloc(size);
        #else
        	return (T* )NewMemClear(T,s);
        #endif
        }
         
        /// ptr can be nullptr.
        /// ptr will be set to nullptr after this call.
        template<typename T>
        void CDFree(T*& ptr) 
        {
        #if API_VERSION < 15000
        	GeFree(ptr);
        #else
        	DeleteMem(ptr);
        #endif
        }
      
    

    Here is short test that work for me on R14.

      
        
        
        	Int32 *t = CDAlloc<Int32>(100);
        	CDFree(t);
        	CDFree(t);
        	t = nullptr;
        	CDFree(t);
      
    

    Remo



  • On 19/11/2013 at 06:36, xxxxxxxx wrote:

    Howdy,

    Ah, so are you saying that adding the "&" references the original pointer, where as the way I have it now, it is only pointing to the original pointer, so GeFree() only sets the "pointer to a pointer" to NULL leaving the original pointer unchanged?

    Adios,
    Cactus Dan



  • On 19/11/2013 at 07:39, xxxxxxxx wrote:

    You won't need to wrap the GeAlloc()/GeFree() calls for R15 if you define the __LEGACY_API for the
    preprocessor.

    Best,
    -Niklas



  • On 19/11/2013 at 07:43, xxxxxxxx wrote:

    Howdy,

    OK, it still crashes when running the debugger, but doesn't crash immediately with the release version.

    Here's the test I did with R12 in the debugger:

    LONG *n = CDAlloc<LONG>(100);
    CDFree(n);
    CDFree(n); // crash immediately in debbugger
    

    So, I changed my CDFree() function to this:

    template<typename T>
    void CDFree(T& ptr)
    {
    #if API_VERSION < 15000
        GeFree(ptr);
    #else
        DeleteMem(ptr);
    #endif
    }
    

    ... and now it doesn't crash in the debugger. 🙂

    Thanks Remo for pointing that out, otherwise I would never have thought to use the & operator. 😉

    Adios,
    Cactus Dan



  • On 19/11/2013 at 08:07, xxxxxxxx wrote:

    Howdy,

    Originally posted by xxxxxxxx

    You won't need to wrap the GeAlloc()/GeFree() calls for R15 if you define the __LEGACY_API for the
    preprocessor.

    Best,
    -Niklas

    Oh? I don't see GeAlloc()/GeFree() in the legacy.h file.

    Besides, I couldn't get that to work, so instead, I simply copied the file, renamed it to "CDLegacy.h" removed the

    #ifdef __LEGACY_API
    

    ...and included it in my R15 projects like this:

    #if API_VERSION > 14999
        #include "CDLegacy.h"
    #endif
    

    To be honest, I'd have preferred the legacy.h file to have been the other way around (typing the new types to the old types), so that I could change all of my code to use the new R15+ types, and then include the legacy.h file with all the older version projects. 😉

    EDIT:
    Ah, OK, I see that GeAlloc()/GeFree() is in c4d_memory.h. But anyway, since I couldn't get the __LEGACY_API defined properly, my wrapper function will do fine. Not only that, but it was a good exercise in template programming. 😉

    Adios,
    Cactus Dan



  • On 19/11/2013 at 08:44, xxxxxxxx wrote:

    ^
    I haven't touched any of the R15 stuff yet. And I probably won't for a while because I refuse to have VS2012 installed on my computer.
    But when Maxon eventually supports VS2013 natively without needing VS2012 installed. I will probably want to start using the new SDK.
    An when I do. The first thing I'm going to look for is a proper tutorial on setting up the __LEGACY_API stuff.

    -ScottA



  • On 19/11/2013 at 08:50, xxxxxxxx wrote:

    Howdy,

    OK, just to double check, I set a couple of breakpoints in the debugger.

    Breakpoint 1:

    Breakpoint2:

    As you can see at the first breakpoint the pointer "n" has a valid address and at the second breakpoint the pointer "n" has been set to NULL. So it's working fine. Thanks again Remo. 😉

    Adios,
    Cactus Dan


Log in to reply