Collector-Safe Value Local Macros (SDK)

3DS Max Plug-In SDK

Collector-Safe Value Local Macros (SDK)

The general approach is to declare special C++ local variables that are known by the collector to contain protected values. You declare them with one of the following macros:

one_value_local(name);

two_value_locals(name1, name2);

three_value_locals(name1, name2, name3);

... etc., up to eight locals.  

They are declared as type Value* to be able to hold any MAXScript value. There are also explicitly typed variants:

one_typed_value_local(type name);

two_typed_value_local(type1 name1, type2 nam2);

...

For example,

two_typed_value_locals(Array* result, String* item);

These locals are implemented as members in a local struct named 'vl', so you work with them as members of that struct:

two_typed_value_locals(Array* result, String* item);

... 

vl.result = new Array (5);

... 

vl.item = new String ("foo");

...

vl.result->append(vl.item);

...

There can be only one value_local declaration macro per C++ block.

Value locals variables must be explicitly dismissed before the block is exited. One way to do this is with the macro:

pop_value_locals();

At this point, the collector protection is lost. In some cases, however, you want to return one of the new values as the result and this value must continue to be protected from the collector. The macro:

return_value(r);

will do this. It both dismisses the value locals and places the return value in a protected area. This return value protection will last as the value passes out through any number of levels of return until the next return_value() use.

In another case, you may have taken a value out of some rooted structure (say an array in a MAXScript global) and want to hand that back as a function result. To protect it against being collected if, for example, that rooted structure gets dropped, you can use the macro:

return_protected(r);

which protects the return value as does return_value(), but doesn't dismiss any value locals.

All functions in the MAXScript core that return potentially new values, including all the new operators, use one of these return value protection schemes. Since this means that a new value returned to you is safe until another function call or operation that might create another new value, you can forego the value_local protection in those cases in which you are immediately returning the new value.

One thing to note about these protected variables is that they are considered to be part of the root set and are scanned by the collector for internal references, so you only need to protect the top-level object if you are constructing some tree of values.

There are some examples of these macros in use in the Scripter-Callable Functions topic.