Assuming unique variable names, the first declaration will be the first occurance of the name within the function, so a
ctrl+F should more or less give the right result immediately.
Though if you’re using a decent IDE/editor, just putting your mouse over the name is usually enough to give you the type.
(Arduino IDE won’t, but VSCode will.)
I think you misread it. Paritcularly the part about:
As for the memory usage, in general a typical implementation will immediately (as you enter the function) allocate the maximum space required for all variables that exist at the same time. However, your declaration habits might affect the exact size of that space.
And the example goes on to demonstrate that.
It’s a bit of an over-simplification, not least because it talks as if the variables are guaranteed to be stored on the stack, but it’s still generally right.
The more complex language-lawyering explanation...
There are rules about side effects and sequencing (formerly ‘sequence points’, now ‘sequenced before’ and ‘sequenced after’),
and ultimately what the compiler can do depends on the semantics of the type.
If you’re dealing with fundamental types or structs of types where all the constructors, destructors and assignment operators are trivial (typically defaulted) then the compiler can reshuffle things as it sees fit (as long as it obeys the ‘as-if’ rule) because a defaulted assignment is just a simple bitwise copy and a defaulted default constructor or destructor effectively means ‘do nothing’.
However, if either the constructor or the destructor are user defined the compiler usually has to assume that there might be side effects and thus has to construct the type at the point of declaration and not tear it down until its enclosing scope actually ends.
Similarly a user-defined assignment operator puts a spanner in the works.
In other words if you were to put
std::vector<int> vector; at the top of your function, the compiler would have to default construct it there and then (which means a dynamic allocation),
and if you had two
std::vectors, the order they are declared in will be the order their destructors are called in.
(The same probably applies to most QT objects, and certainly applies to things like file handles, smart pointers and other container types.)
But even if you’re dealing only with trivial types,
the compiler may end up producing less efficient code for variables that are given a longer lifetime than necessary simply because it affects how the compiler decides to allocate resources.
Particularly if the types involved are large enough that they must be allocated on the stack and can’t be stored in a register,
and particularly if the code is complex or involves loops.
That’s just bad style regardless.
Stylistic issues aside, too much code in a single function tends to upset the compiler.
The compiler prefers short digestable chunks,
otherwise there’s too much scope to keep track of and comprehend,
and it can’t do as good a job as if you split the code up into many smaller functions.
That reminds me of another issue...
Often people try to reuse variables, presumably due to some ill-concieved notion that doing so is somehow more efficient because it’s reusing memory, but the reverse is actually true.
(I won’t go into the mechanics of it now because that’ll add another paragraph or two, but basically it’s to do with lifetimes and resource allocation.)
It’s more or less functionally equivalent to just writing a custom function to do the initialising, which could have been done back in C++03,
but lambdas have two advantages:
they can capture variables in the parent scope (by value or by reference),
and they can be anonymous so you don’t have to name them.
Personally speaking I haven’t encountered a situation where I’ve needed to do that,
and I’d be tempted to create a named function anyway,
unless it genuinely was a one-off and I was sure I’d never want to do the same thing again.
It seems to me that it’s more likely to be the file acesses.
You’d probably get better performance if you just parsed the basic descriptions/metadata from the
.csv and then lazy-loaded the graphics and game data on demand.
(After all, you probably don’t need to load the game data unless an upload has been requested.)