You cannot mix native C/C++ memory (i.e., local stack variables or allocated variables with malloc & cousins) into an mxArray for returning to the MATLAB workspace. That will eventually lead to crashing MATLAB when it tries to free this memory. So you are stuck with duplicating this memory. As I see it your options are:
1) Rewrite your code to create your C/C++ structure using MATLAB API functions mxMalloc & cousins instead of native C/C++ functions malloc & friends. Then this memory could be directly attached to an mxArray struct for returning to the MATLAB workspace ... no duplication or deallocation would be required.
2) Create your MATLAB struct piecemeal with mxMalloc & cousins as you deallocate the C/C++ memory piecemeal. This would still require you to duplicate the largest block temporarily, but saves you from duplicating everything in memory at the same time.
3) Ignore what I said about mixing native C/C++ memory and MATLAB API memory. Play games with hacking into the mxArray to mix them, keep shared data copies of them inside the mex routine to prevent MATLAB from attempting to free the memory. This is very tricky and is not recommended since you can easily leak memory and/or crash MATLAB if you don't manage everything correctly.
It doesn't save you any significant amount of memory returning several individual variables to MATLAB vs returning a struct or cell array, so just return whatever is easier to create and manage based on your intended use.