BaseContainer FlushAll crashes
-
In continuation from the disussion concerning ToolData container, I am encountering an issue I cannot seem to put my finger on. So I extracted the offending code into a separate dummy plugin.
The whole code is below.
A command data when executed will parse theLive Selection
description and store all settings into a basecontainer, which is located in a separate class.When Cinema 4D is then closed the class hosting the basecontainer is destroyed, which calls the basecontainer's destructor, which will perform a
FlushAll
.
For one reason or another this call crashes.I have pinpointed the issue to the
SplineData
which is part of the soft-selection settings of the Live Tool (while not actively shown this attribute is still part of the description).
This SplineData is a custom data type, and when I omit copying this attribute into the test basecontainer all goes well when class is destroyed.To me, it seems as if copying the data into the container does not make a copy, but uses the original pointer. Hence, when the test class and its test basecontainer is destroyed it will try to destroy the SplineData ... which has already been destroyed as a result of Cinema 4D closing (... at least, that's my guess).
If I store the settings into a basecontainer of the command data then there seem to be no problem.
Which does make me think I am doing something wrong with my test class allocation/deallocation.
I just cannot seem to see what exactly it is I am doing wrong.Tried with R16, R17, ...
// ======================== // Testing // Dummy "empty" plugin // ======================== #include "c4d.h" // Dummy IDs - for demonstration purposes only #define MYCOMMAND_PLUGIN_ID 1999999 class Test { public: Test() {} virtual ~Test() {} BaseContainer mTestContainer; }; Test* gTest = nullptr; // ==================================== // CommandData // ==================================== class MyCommand : public CommandData { INSTANCEOF(MyCommand, CommandData) public: virtual Bool Execute(BaseDocument* doc); virtual Bool ExecuteSubID(BaseDocument* doc, Int32 subid); virtual Int32 GetState(BaseDocument* doc); virtual Bool RestoreLayout(void* secret); virtual Bool Message(Int32 type, void* data); // BaseContainer mToolData; }; Bool MyCommand::Execute(BaseDocument* doc) { // get the live selection description const Int32 id = ID_MODELING_LIVESELECTION; BasePlugin* plug = FindPlugin(id, PLUGINTYPE_TOOL); // needs explicitely to be PLUGINTYPE_TOOL, as PLUGINTYPE_ANY does not work correctly if (!plug) return FALSE; AutoAlloc<Description> desc; if (desc && plug->GetDescription(desc, DESCFLAGS_DESC_0)) { void *handle = desc->BrowseInit(); DescID dcid, groupid; GeData gd; const BaseContainer *objBc = NULL; while (desc->GetNext(handle, &objBc, dcid, groupid)) { if (objBc) { const String name = objBc->GetString(DESC_NAME); const Int32 id = dcid[0].id; plug->GetParameter(DescID(dcid), gd, DESCFLAGS_GET_0); const Int32 type = gd.GetType(); // attributes can be buttons, bars, ... // anything without a user input value, skip these if (type == DA_NIL) continue; //mToolData.SetData(id, gd); gTest->mTestContainer.SetData(id, gd); } } desc->BrowseFree(handle); //Free the memory used by the Browse function } return TRUE; } Bool MyCommand::ExecuteSubID(BaseDocument* doc, Int32 subid) { return TRUE; } Int32 MyCommand::GetState(BaseDocument* doc) { return CMD_ENABLED; } Bool MyCommand::RestoreLayout(void* secret) { return TRUE; } Bool MyCommand::Message(Int32 type, void* data) { return SUPER::Message(type, data); } Bool RegisterMyCommand(void) { return RegisterCommandPlugin(MYCOMMAND_PLUGIN_ID, "Testing", 0, AutoBitmap("icon.png"), "Test", NewObjClear(MyCommand)); } // ==================================== // Plugin Main // ==================================== Bool PluginStart(void) { RegisterMyCommand(); gTest = NewObjClear(Test); if (!gTest) return FALSE; return TRUE; } void PluginEnd(void) { if (gTest) { gTest->mTestContainer.FlushAll(); // This line was added for testing out the flushing -> it crashes ... why? // without the above line, the destructor of the Test class would call BaseContainer's destructor, which would perform a FlushAll -> this crashes DeleteObj(gTest); } } 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; }
-
Hi @C4DS
You should free your stuff in C4DPL_ENDACTIVITY.
Documentation of PluginEnd will be improved to point to C4DPL_ENDACTIVITY, in any case, see Plugin Functions Manual.
Cheers,
Maxime. -
Seems I have been doing it wrong for all those years.
Thanks for leading me onto the right path ...