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.