R17 vs R19 cannot access private member



  • On 14/12/2017 at 07:04, xxxxxxxx wrote:

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

    ---------
    I am developing a plugin for R19 using Visual Studio 2015 and the R19 SDK, all is building and working as expected.
    I then use a duplicate of the plugin project to build for R17 using the R17 SDK, still using the Visual Studio 2015 but setting up the project to use Platform toolset v120 for Visual Studio 2013 (since this is what R17 SDK supports).

    I now get an error:

      
    d:\projects\dev\PluginName\source\changehandler.h(43) : error C2248: 'AutoAlloc<BaseLink>::AutoAlloc' : cannot access private member declared in class 'AutoAlloc<BaseLink>' (..\source\ChangeHandler.cpp)  
    1>          d:\projects\dev\frameworks r17\cinema.framework\source\ge_autoptr.h(41) : see declaration of 'AutoAlloc<BaseLink>::AutoAlloc'  
    1>          This diagnostic occurred in the compiler generated function 'TagInfo::TagInfo(const TagInfo &)'  
    1>          d:\projects\dev\frameworks r17\cinema.framework\source\ge_autoptr.h(41) : see declaration of 'AutoAlloc<BaseLink>::AutoAlloc'  
    

    The culprit seems to be a missing copy constructor in my struct:

      
    // container holding tag information while traversing the scene hierarchy,  
    // for detetcting deleted and renamed tags  
    struct TagInfo {  
      AutoAlloc<BaseLink> mTagLink;  
      AutoAlloc<BaseLink> mHostObjectLink;  
      
      TagInfo() { TagInfo(nullptr); }  
      TagInfo(BaseTag* tag)  
      {  
          mTagLink->SetLink(tag);  
          BaseObject* hostObject = tag ? tag->GetObject() : nullptr;  
          mHostObjectLink->SetLink(hostObject);  
      }  
      
    };  
    

    I have looked at the include files of AutoAlloc, BaseLink, BaseArray but see no difference between the R17 and R19 files.

    So what is the reason I don't have a problem building the R19 project, while I get this "cannot access private member" when building the R17 project.
    I don't get it.



  • On 15/12/2017 at 05:19, xxxxxxxx wrote:

    I forgot to mention that the issue was related to a BaseArray where I append a TagInfo, resulting in the compiler error mentioned above.

    Looked into the Append implementation and noticed that a std::move is used (same in R17 and R19), as such I tried to implement a move constructor for my struct

      
      TagInfo(TagInfo&& ti)  
      {  
          mTagLink.Assign(ti.mTagLink.Release());  
          mHostObjectLink.Assign(ti.mHostObjectLink.Release());  
      }  
    

    This resolved the compiler error and the implementation works in both releases, but now I get a memory leak

      
    Memory Leaks Detected:  
    p:\c4d_perforce_work\release\19.0\modules\c4dplugin\source\src\philip\pluginsystem\operatingsystem.cpp (7869) : 4 Memory leaks of 32 bytes (, first leak at 000000F7647A4E40)  
    1 blocks not freed  
    

    So, is my move constructor not correct?
    Am I missing something?



  • On 15/12/2017 at 06:19, xxxxxxxx wrote:

    Hi Daniel, thanks for writing us.

    I tried to replicate the issue but I didn't succeeded: actually I was able to compile a dummy project on R19 and then, operating the proper modifications, to compile it on R17.

    Just to be sure we are on the same page, in order to move between toolsets remind to:

    1. change in the VC solution (.sln) the path to the right Cinema Framework
    2. change in the VC project (.vcxproj) the path to the ProjectReference (it should be located in the tail of the file)
    3. change in the VC Property (.props) the path to the MAXON_ROOTDIR (it should be located at the beginning of the file)

    Were all the three changes applied on you project/solution before trying to compile? If not you could pretty likely trying to compile your R17 plugin pointing to the R19 framework.

    Looking forward further detail, give best.
    Riccardo



  • On 15/12/2017 at 07:05, xxxxxxxx wrote:

    I have setup in the past the different SDKs next to each other., which are now used by several plugin projects.

    Per plugin project I have for each Cinema 4D version a separate solution, including the appropriate framework project.
    This has worked till now with R16, R17, R19.
    So in order to build a plugin for a particular version of Cinema 4D, I simply open the appropriate solution and start building. All solutions use the same source and header files.
    For some changes in the API I have provided preprocessors to allow the same source to be used by any solution.
    Each solution uses the appropriate toolset and framework.

    Additionally, I have tried running the built plugin with the meant version of Cinema 4D.
    (plugin R19 on Cinema R19, plugin R17 on Cinema R18, etc ....)
    I assume that a plugin build with R19 would not run on Cinema 4D R18 or before?
    So, I am pretty sure that the problem is not related to toolset, framework or project.

    Besides, when adding the move constructor to my struct the compile error is resolved.

    I just noticed that I never updated my R17 from 17.053 to the latest 17.055, but I don't see any changes to the API so I guess I am still save using the R17.053 SDK.



  • On 16/12/2017 at 02:41, xxxxxxxx wrote:

    Here is a testing plugin with minimal code which results in a correctly built R19 plugin, and fails with the compiler error mentioned when copying the R19 plugin project and replacing all R19 framework references by R17 ... unless I comment out the move constructor of the TagInfo struct, but then I get memory leaks (both in R19 and R17).

      
    // ========================  
    // Testing  
    // Parsing hierarchy - checking for deleted tags  
    // ========================  
      
    #include "c4d.h"  
    #include "hashmap.h"  
    #include "c4d_baselinkarray.h"  
      
    #include "Tmytag.h" // tag resource  
      
    // Dummy IDs - for demonstration purposes only  
    #define TAGDATA_PLUGIN_ID        1999998  
    #define MESSAGEDATA_PLUGIN_ID    1999999  
      
    //  
    // TagData  
    //  
    class MyTagData : public TagData  
    {  
      INSTANCEOF(MyTagData, TagData)  
      
    public:  
      static NodeData* Alloc(void) { return NewObjClear(MyTagData); }  
    };  
    Bool RegisterMyTagData()  
    {  
      return RegisterTagPlugin(TAGDATA_PLUGIN_ID, "tagstring", TAG_VISIBLE, MyTagData::Alloc, "Tmytag", AutoBitmap("icon.png"), 0);  
    }  
      
      
    // container holding tag information while traversing the scene hierarchy,  
    // for detetcting deleted and renamed tags  
    struct TagInfo {  
      AutoAlloc<BaseLink> mTagLink;  
      AutoAlloc<BaseLink> mHostObjectLink;  
      
      TagInfo() { TagInfo(nullptr); }  
      TagInfo(BaseTag* tag)  
      {  
          mTagLink->SetLink(tag);  
          BaseObject* hostObject = tag ? tag->GetObject() : nullptr;  
          mHostObjectLink->SetLink(hostObject);  
      }  
      // ----- needed for R17 build to compile -----  
      // move constructor  
      /*TagInfo(TagInfo&& ti)  
      {  
          mTagLink.Assign(ti.mTagLink.Release());  
          mHostObjectLink.Assign(ti.mHostObjectLink.Release());  
      }*/  
    };  
    typedef maxon::BaseArray<TagInfo> TagInfoListType;  
      
    // helper hashmap containing tag as key, and index in TagInfoList array  
    typedef maxon::HashMap<BaseTag*, Int32> HelperHashMapType;  
      
    //  
    // MessageData  
    //  
    class MyMessageData : public MessageData  
    {  
    public:  
      
      TagInfoListType    mTagList;  
      
      virtual Bool CoreMessage(Int32 id, const BaseContainer &bc)  
      {  
          // we are only interested in EVMSG_CHANGE  
          // skip every other message  
          if (id != EVMSG_CHANGE)  
              return TRUE;  
          BaseDocument* doc = GetActiveDocument();  
          if (!doc)  
              return TRUE;  
      
          ParseHierarchy(doc);  
      
          return TRUE;  
      }  
      
      BaseObject* GetNextObject(BaseObject* object)  
      {  
          if (!object) return nullptr;  
          if (object->GetDown()) return object->GetDown();  
          while (!object->GetNext() && object->GetUp())  
              object = object->GetUp();  
          return object->GetNext();  
      }  
      void ParseHierarchy(BaseDocument* doc)  
      {  
          if (!doc)  
              return;  
      
          HelperHashMapType helper;  
      
          // ===== handle deleted tag ====  
          // and prepare a helper hashmap  
      
          TagInfoListType::Iterator itr = mTagList.Begin();  
          while (itr != mTagList.End())  
          {  
              BaseTag* tag = (BaseTag* )itr->mTagLink->GetLink(doc);  
              BaseObject* hostObject = (BaseObject* )itr->mHostObjectLink->GetLink(doc);  
      
              // an helper (with the tag pointer as key and the index in the taglist as value)  
              // is used while parsing the scene hierarchy to perform a find, resulting in the index in the list  
              Int32 idx = (Int32)(itr - mTagList.Begin());  
      
              if (tag)  
              {  
                  // store the tag and its index in the list into the helper map  
                  helper.Put(tag, idx);  
                  itr++;  
              }  
              else  
              {  
                  // tag is deleted, remove it from list  
                  itr = mTagList.Erase(itr);  
      
                  // do other things  
                  // ...  
      
                  // following lines are to avoid compiler warning on unused "hostObject"   
                  if (hostObject)  
                      hostObject->GetName();  
      
              }  
          }  
      
          // ===== handle new or existing tag ====  
          // parsing the scene  
      
          BaseObject* object = doc->GetFirstObject();  
          while (object)  
          {  
              BaseTag* tag = object->GetTag(TAGDATA_PLUGIN_ID);  
              if (tag)  
              {  
      
                  HelperHashMapType::Entry* e = helper.FindEntry(tag);  
                  if (!e)  
                  {  
                      // tag is not part of our hashmap (and thus not part of our list)  
                      // -> new tag has been inserted into the scene,  
                      // add it to our list  
      
                      mTagList.Append(TagInfo(tag));  
      
                  }  
                  else  
                  {  
                      // tag already in hashmap (and list)  
                      // get the index in the list from the helper hashmap  
      
                      Int32 idx = e->GetValue();  
      
                      // ...  
      
                      // following lines are to avoid compiler warning on unused "idx"   
                      BaseObject* hostObject = (BaseObject* )mTagList[idx].mHostObjectLink->GetLink(doc);  
                      if (hostObject)  
                          hostObject->GetName();  
      
                  }  
              }  
      
              object = GetNextObject(object);  
          }  
      }  
    };  
    Bool RegisterMyMessageData(void)  
    {  
      return RegisterMessagePlugin(MESSAGEDATA_PLUGIN_ID, String(), 0, NewObj(MyMessageData));  
    }  
      
      
    //  
    // Plugin Main   
    //  
    Bool PluginStart(void)  
    {  
      RegisterMyTagData();  
      RegisterMyMessageData();  
      
      return TRUE;  
    }  
    void PluginEnd(void)   
    {  
    }  
    Bool PluginMessage(Int32 id, void * data)  
    {  
      switch (id) {  
      case C4DPL_INIT_SYS:  
          if (!resource.Init())  
              return FALSE;  
          return TRUE;  
      case C4DMSG_PRIORITY:  
          return TRUE;  
      case C4DPL_BUILDMENU:  
          break;  
      case C4DPL_ENDACTIVITY:  
          return TRUE;  
      }  
      return FALSE;  
    }  
      
    

    EDIT
    There are currently 2 issues in this topic now: the compiler error in R17 and the memory leak in both R17 and R19.
    While I still wonder why the compiler errors occurs with R17 framework, I am fine with the idea that it is fixed by providing a move constructor. The main issue then remains, why do I get a memory leak in case the move constructor is implemented.



  • On 16/12/2017 at 05:22, xxxxxxxx wrote:

    FIXED !!!

    Using the code below, fixes the memory leak.
    At least with Visual Studio. Still have to figure out if that's OK with Xcode on MacOS

      
      // move constructor  
      TagInfo(TagInfo&& ti) :  
          mTagLink(std::move(ti.mTagLink)),  
          mHostObjectLink(std::move(ti.mHostObjectLink))  
      {}  
      MAXON_OPERATOR_MOVE_ASSIGNMENT(TagInfo);  
      
    

Log in to reply