Reference System Best Practices
The following is a list of best practices regarding usage of the reference system:
- Make sure you choose correctly between storing a pointer or a reference in your plug-in
to a scene entity. Storing a pointer to a scene entity is seldom safe because the
pointer could become invalid if the scene entity is deleted and your plug-in fails
to update the pointer. Although pointers to scene entities could be used as local
variables in plug-in member functions, they should not be cached as plug-in data members
and their life span should be as short as possible.
For information on converting pointers to weak or indirect references see Using Indirect References Instead of Pointers.
References can be stored as plug-in member variables but it is the plug-in's responsibility
to properly implement their management, so that they do get updated, do not prevent
the dependent entity to be destroyed, etc.
- When observing nodes always use weak references instead of strong references. This
is because nodes can be deleted by the user.
- Make sure you choose the right type of reference your plug-in needs to create to
a scene entity it depends on. See the topic Choosing the Kind of Reference for more information.
- Never store pointers to scene nodes as plug-in data members because they can be invalidated
at any time (e.g. due to the user deleting them). Use a node monitor instead (INodeMonitor or INodeTransformMonitor).
- A plug-in's implementation of ReferenceMaker::SetReference() should always assign the ReferenceTarget passed in by the caller to the corresponding plug-in data member, as opposed to implementing
its own logic to update that reference.
- A plug-in that needs to maintain a variable number of references, should use the
class IRefTargContainer.
- In order to allow 3ds Max to manage the life-time of your plug-in instances, the
plug-in would not override Animatable::DeleteThis() or ReferenceTarget::AutoDelete(). When a plug-in needs to behave as a singleton, it should overwrite ReferenceTarget::AutoDelete() to return REF_SUCCEED. In this case, the plug-in should take care of deleting itself its sole instance
since 3ds Max will not be able to do it.
- Do not call the delete operator on a pointer to an object derived from Animatable or any of its sub-classes. For more information see Manual Deallocation of Referenced Objects.
- For managing one single reference, a plug-in should consider using an instance of
class SingleRefMaker or class SingleWeakRefMaker.
- Initialize ReferenceTarget pointers to NULL before the first call to ReferenceMaker::ReplaceReference(). This should be done in the member initialization list of the constructor.
- When receiving a REFMSG_TARGET_DELETED message a ReferenceMaker should always set its reference to the ReferenceTarget instance being deleted to NULL.
- If the plug-in wishes to delete itself in response to REFMSG_TARGET_DELETED, it should return REF_AUTO_DELETE from its implementation of ReferenceMaker::NotifyRefChanged().
- Never call ReferenceMaker::SetReference(), always call ReferenceMaker::ReplaceReference() instead.
- Use Animatable::GetAnimByHandle() and compare the result to NULL to verify that an animatable (or ReferenceTarget) pointer is valid.
- If appropriate call ReferenceMaker::DeleteAllRefs() in the destructor of a plug-in that derives from reference maker, to assure that
all references are deleted. Normally if an object is deleted correctly then this shouldn't
be necessary.
- Send reference messages sparingly. They can slow down the system. For example if
a large number of changes are made to a plug-in at once, then the plug-in should try
to send only a single REFMSG_CHANGE message for the set of changes.
- When setting ReferenceTarget pointers to NULL in repsonse to REFMSG_TARGET_DELETED, be sure to only assign one pointer to the ReferenceTarget to NULL in the case that you have multiple references to the same target.
- A reference maker should support the setting of NULL references for any of its reference indexes.