Postponing variable definitions as long as possible increases program clarity and improves progranm efficiency.
After defining a variable of a type with a constructor or destructor, there’s a cost of construction when control reaches a variable’s definition, and a cost of destruction when the variable goes out of scope. If the variable is unused, the cost is wasted, which is the case we want to avoid.
Nobody declares unused variables on purpose, but chances are we may still encounter them unexpectedly: suppose there’s a function that returns an encrypted version of a password as long as the password is long enough and may throw an exception of type logic_error
(defined in standard C++ library, item 54) if the passwod is too short:
|
|
Apparently, the object encrypted
is unused if an exception is thrown, and we still have to pay the cost of construction and destruction of encrypted
.
A better solution is to postpone encrypted
’s definition until we know we’ll need it:
|
|
This code still isn’t as tight as it might be, because encrypted
is defined without any initialization arguments, leading to its default constructor getting called and an extra aassignment operation being used later. As item 4 suggests,
default-constructing an object and then assigning to it is less efficient than initializing it with the value we really want it to have.
Suppose the hard part of encryptPassword
is performed in this function:
|
|
Then we’d better skip the pointless and potentially expensive default construction, directly initializing encrypted
with password
until right before we have to use the variable:
|
|
This gives us certain benifits:
- we avoid constructing and destructing unneeded obejcts
- we avoid unnecessary default constructions
- we help document the purpose of variables by initializing them in contexts in which their meaning is clear
Loop
If a variable is used only inside a loop, should we define it outside the loop and make an assignment to it on each loop iteration, or to define the variable inside the loop?
|
|
|
|
Let’s see the costs of the two approaches above:
- Approach A: 1 constructor + 1 destructor + n assignments
- Approach B: n constructor + n destructors
Since Approach A makes the name w
visible in a larger scope than Approach B, which is contrary to program comprehensibility and maintainability, generally we choose Approach B as default, unless we know that
- assignment is less expensive than a constructor-destructor pair
- we’re dealing with a performance-sensitive part of our code