You can't re-use mxArray variables like you are doing when you are building a cell or struct array in a mex routine. There is an official way to fix this, and an unofficial way to fix this. The official way, which has the downside of requiring a deep data copy, is:
mxSetField(subMexMsg, 0, "field3", inputMxArray);
mxSetField(mexMsg, 0, "field1", subMexMsg);
mxSetField(mexMsg, 0, "field2", mxDuplicateArray(inputMxArray));
That is, every time you re-use a variable as a cell or struct element, you must actually use a deep data copy of it. Not very memory efficient if you have large variables, but that is the way it is. The reason your code is seg faulting is because when the 1st reference to inputMxArray gets destroyed, the memory for it is actually free'd. Then when the 2nd reference to inputMxArray gets destroyed, the memory for it has already been free'd so invalid memory is accessed. MATLAB didn't know there was another reference to the variable in memory when the 1st reference was destroyed.
MATLAB can, and does at the m-file level, re-use variables the way you are doing, but it increments a "reference count" for the variable to keep track of how many copies are around in cell and struct variables. It does this automatically in the background. That way, when variables get cleared, memory doesn't actually get free'd until the last reference copy gets cleared. I.e., when the 1st reference to inputMxArray gets destroyed, the only thing that happens is the reference count gets decremented by 1. No memory is free'd. When the 2nd reference to inputMxArray gets destroyed, the memory actually gets free'd since it is the last copy in memory.
There is no official way to duplicate this behavior in a mex routine using only official API routines. There is an unofficial mex routine called mxCreateReference, that will do this for you (i.e., increment the reference count by 1 instead of creating a deep data copy). To use it, simply include the prototype and call it (but you will be departing from official library code). The mxCreateReference function is intended specifically for re-using variables in cell or struct variables. E.g.,
mxArray *mxCreateReference( mxArray * );
:
mxSetField(subMexMsg, 0, "field3", inputMxArray);
mxSetField(mexMsg, 0, "field1", subMexMsg);
mxSetField(mexMsg, 0, "field2", mxCreateReference(inputMxArray));
The return value (mxArray address) is the same as the input value.
Unfortunately, TMW has removed mxCreateReference in later versions of MATLAB. The only recourse left to the programmer at this point would be to hack into the mxArray to bump up the reference count manually. Let me know if you need this.
For comparison, mxSetField, mxSetFieldByNumber, and mxSetCell do the following to the input variable:
1) Changes the variable type to 3 (SUB_ELEMENT)
2) Removes the variable address from the garbage collection
Best Answer