If your type (and all its transitive base classes) meets the rules for a
C++ aggregate (no virtual functions, no protected/private fields, no user-declared/inherited constructors), the clang plugin will no longer warn about complex constructors and destructors [1].
This allows you to use designated initializers or ensure your type is trivially copyable for shared memory.
Use a struct only for passive objects that carry data; everything else is a class. [...] If more functionality or invariants are required, or struct has wide visibility and expected to evolve, then a class is more appropriate. If in doubt, make it a class.
Finally, if your type does not need to be an aggregate, it's still better to define your constructors/destructors out of line [2].
Daniel
[1] An astute reader might notice that having a user-declared destructor does not disqualify a type from being an aggregate; however, a user-declared destructor prevents the compiler from synthesizing an implicitly-declared move constructor, which results in worse outcomes overall.
[2] There is a modest increase in binary size with implicitly-defined constructors/destructors;
https://crrev.com/c/7763597 contains numbers from converting 61 candidate types to use designated initializers.