App: make deleting dynamic property safer
Dynamic property can be removed at any time, even during triggering of onChanged() signal of the removing property. This patch introduced static function Property::destroy() to make it safer by queueing any removed property, and only deleting them when no onChanged() call is active.
This commit is contained in:
@@ -1010,7 +1010,7 @@ bool Document::redo(int id)
|
||||
|
||||
void Document::addOrRemovePropertyOfObject(TransactionalObject* obj, Property *prop, bool add)
|
||||
{
|
||||
if (!prop || !obj)
|
||||
if (!prop || !obj || !obj->isAttachedToDocument())
|
||||
return;
|
||||
if(d->iUndoMode && !isPerformingTransaction() && !d->activeUndoTransaction) {
|
||||
if(!testStatus(Restoring) || testStatus(Importing)) {
|
||||
|
||||
@@ -215,7 +215,7 @@ bool DynamicProperty::removeDynamicProperty(const char* name)
|
||||
throw Base::RuntimeError("property is not dynamic");
|
||||
Property *prop = it->property;
|
||||
GetApplication().signalRemoveDynamicProperty(*prop);
|
||||
delete prop;
|
||||
Property::destroy(prop);
|
||||
index.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -138,8 +138,48 @@ ObjectIdentifier Property::canonicalPath(const ObjectIdentifier &p) const
|
||||
return p;
|
||||
}
|
||||
|
||||
static std::vector<Property*> _RemovedProps;
|
||||
static int _PropCleanerCounter;
|
||||
|
||||
struct PropertyCleaner {
|
||||
PropertyCleaner(Property *p)
|
||||
: prop(p)
|
||||
{
|
||||
++_PropCleanerCounter;
|
||||
}
|
||||
~PropertyCleaner() {
|
||||
if(--_PropCleanerCounter)
|
||||
return;
|
||||
bool found = false;
|
||||
while(_RemovedProps.size()) {
|
||||
auto p = _RemovedProps.back();
|
||||
_RemovedProps.pop_back();
|
||||
if(p != prop)
|
||||
delete p;
|
||||
else
|
||||
found = true;
|
||||
}
|
||||
if(found)
|
||||
_RemovedProps.push_back(prop);
|
||||
}
|
||||
|
||||
Property *prop;
|
||||
};
|
||||
|
||||
void Property::destroy(Property *p) {
|
||||
if(p) {
|
||||
// Is it necessary to nullify the container? May cause crash if any
|
||||
// onChanged() caller assumes a non-null container.
|
||||
//
|
||||
// p->setContainer(0);
|
||||
|
||||
_RemovedProps.push_back(p);
|
||||
}
|
||||
}
|
||||
|
||||
void Property::touch()
|
||||
{
|
||||
PropertyCleaner guard(this);
|
||||
if (father)
|
||||
father->onChanged(this);
|
||||
StatusBits.set(Touched);
|
||||
@@ -152,6 +192,7 @@ void Property::setReadOnly(bool readOnly)
|
||||
|
||||
void Property::hasSetValue(void)
|
||||
{
|
||||
PropertyCleaner guard(this);
|
||||
if (father)
|
||||
father->onChanged(this);
|
||||
StatusBits.set(Touched);
|
||||
|
||||
@@ -104,6 +104,9 @@ public:
|
||||
Property();
|
||||
virtual ~Property();
|
||||
|
||||
/// For safe deleting of a dynamic property
|
||||
static void destroy(Property *p);
|
||||
|
||||
/** This method is used to get the size of objects
|
||||
* It is not meant to have the exact size, it is more or less an estimation
|
||||
* which runs fast! Is it two bytes or a GB?
|
||||
|
||||
Reference in New Issue
Block a user