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.
Be very careful if holding a pointer to a scene entity in a local variable when making system calls that may cause that scene entity to be deleted. Do not rely on Restore Objects being created to prevent scene entity deletion as, particularly when dealing with MAXScript, the hold system may be suspended. In such cases, instead of directly holding a pointer you should hold the pointer via a
SingleRefMaker
,SingleWeakRefMaker
,TypedSingleRefMaker
, orTypedSingleWeakRefMaker
.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 Kinds of References 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
orINodeTransformMonitor
).A plug-in's implementation of
ReferenceMaker::SetReference()
should always assign theReferenceTarget
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()
orReferenceTarget::AutoDelete()
. When a plug-in needs to behave as a singleton, it should overwriteReferenceTarget::AutoDelete()
to returnREF_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 Reference Object Lifetime Management.For managing one single reference, a plug-in should consider using an instance of class
SingleRefMaker
or classSingleWeakRefMaker
.Initialize
ReferenceTarget
pointers toNULL
before the first call toReferenceMaker::ReplaceReference()
. This should be done in the member initialization list of the constructor.When receiving a
REFMSG_TARGET_DELETED
message aReferenceMaker
should always set its reference to theReferenceTarget
instance being deleted toNULL
.If the plug-in wishes to delete itself in response to
REFMSG_TARGET_DELETED
, it should returnREF_AUTO_DELETE
from its implementation ofReferenceMaker::NotifyRefChanged()
.Never call
ReferenceMaker::SetReference()
, always callReferenceMaker::ReplaceReference()
instead.Use
Animatable::GetAnimByHandle()
and compare the result toNULL
to verify that an animatable (orReferenceTarget
) 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 toNULL
in repsonse toREFMSG_TARGET_DELETED
, be sure to only assign one pointer to theReferenceTarget
toNULL
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.