The caller must make sure ModelData remains valid throughout the call. ModelData is not required anymore after the model has been created. The caller can decide to convert the result into a shared pointer if required (e.g. if the model needs to be shared with an async task for evaluation).