You're effectively talking about the distinction between "value initialization" (T{}
) and "here's a list of values that happens to be empty" (T({})
). I would say that best practices should be to do the thing that best describes your intent.
There is a difference between value initializing a vector
and initializing one from a list that just so happens to be empty. In the latter case, you may someday add one or more elements to that list. In the former case, you never will. So you need to do what best describes the meaning of your code.
As for the question of efficiency, it almost certainly does not matter. You should start from the perspective of code clarity; if performance becomes an issue, you can adjust it later. The choice between "empty list" and "value initialization" is first and foremost about communicating your intent.
I understand that, in theory, by using the types short, int, and long, you let the compiler choose the length that is most efficient for the given processor.
That is only partially true. All those types have a guaranteed minimum size in ANSI C (AFAIK even in ANSI C89). Code relying only on those minimum sizes is still portable. Cases where the maximum size of a type matters to portability are way less frequent. Said that, I have seen (and written) lots of code over the years where int
was assumed to be 32 bit as minimum, written clearly for environments with >=32 bit CPUs at minimum.
But is this a case of premature optimization [...]?
Premature optimization is not only about optimizing for speed. It is about investing extra effort into code, and making code more complicated, for a (often pathological) "just in case" reason. "Just in case it could be slow" is only one of those potential reasons. So avoiding the usage of int
"just in case" it could be ported to a 16 bit platform in the future could also be seen as a form of premature optimization, when this kind of porting will likely never happen.
Said that, I think the part you wrote about int
is to some degree correct: in case there is any evidence a program might get ported from a 32 to a 16 bit platform, it would be best not to rely on int
having 32 bits, and to use either long
, a specific C99 data type like int32_t
or int_least32_t
whereever one is unsure whether 16 bits are enough, or not. One could also use a global typedef
to define int32_t
on platforms which are not C99 compliant. All of this is a little bit of extra effort (at least in teaching the team which special data types were used in the project, and why).
See also this older SO article, for which the top most answer says, most people don't need that degree of portability.
And to your example about the GUID structure: the shown data structure seems to be mostly ok, it uses data types which are guaranteed to be large enough for each of the parts on each ANSI compliant platform. So even if someone tries to use this structure for writing portable code, that would perfectly be possible.
As you noted by yourself, if someone would try to use this structure as a spec for a GUID, they could complain about the fact it is to some degree imprecise and that it requires the read the documentation in full for getting an unambigous spec. This is one of the less frequent cases where maximum size of the types may matter.
Other problems could arise when the content of such a struct
is string-formatted, binary serialized, stored or transmitted somewhere, whilst making assumptions about the individual maximum size of each field, or the total size being exactly 128 bit, the endianness, or the precise binary encoding of those data types. But since the documentation of the GUID struct does not make any promises about the underlying binary representation, one should not make any assumptions about it when trying to write portable code.
Best Answer
Most of the time the space cost is negligible and you shouldn't worry about it, however you should worry about the extra information you are giving by declaring a type. For example, if you:
You are giving a useful piece of information to another developer: salary cannot be negative.
The difference between short, int, long is rarely going to cause space problems in your application. You are more likely to accidentally make the false assumption that a number will always fit in some datatype. It's probably safer to always use int unless you are 100% sure your numbers will always be very small. Even then, it is unlikely to save you any noticeable amount of space.