There could be a lot of side discussion here, such as syntactic convenience and performance, but those issues are secondary in my opinion.
Ultimately it boils to what are the "invariants" of the class.
If you do intrusive serialization you are open to breaking the class invariant from outside the program.
Specially if anyone (including a program) can change the serialization medium.
Of course you could check the invariant in your intrusive serialize
function (and fail somehow if they are violated) but that is not always possible.
For example, if you work with a class with very complex invariants (or invariants that cannot be expressed in code), basically the only way to guarantee the invariant is to deserialize through a constructor (and possibly other public operations on the class) which is basically a non-intrusive way.
In other words, intrusive serialization is unsafe because it can be a backdoor to leave your program in an invalid state, which can be a security issue.
If your class have no invariants (e.g. std::pair<T1, T2>
) you can use either.
Otherwise use non-intrusive serialization if you can, this way you can be sure that the original invariants of the class are respected.
Intrusive serialization is in general more efficient but checking invariants can be either costly or impossible.
Finally, if you can't serialize or deserialize non-intrusively that can be code-smell.
Either because your interface is lacking or because your class doesn't deserve to be serialized.
Only objects that are "self contained" logically deserve to be serialized.
That is objects that can take "values" beyond/outside the context of the program or your computer.
In the nomenclature of the C++ "Regular" or "Value Types" are the only ones that should be serializable.
Programs with "incidental data structures" (classes connected to many other classes, as you mention) tend to have components that cannot be individually serialized.
At best the whole state of the program needs to be serialized, and that is obviously a problem.