Reputation: 8310
What is the pratical utility of declaring a static variable in function? I understood the lifetime of a static variable declared within a function, but I can not figure a practical example where it might be useful (or necessary) to declare a static variable in a function. Could you give me an example of a problem that should be solved in this way?
Upvotes: 4
Views: 248
Reputation: 13828
Adding to other answers, you also need to remember that in C++, the static
keyword has many meanings. In a function body, it also changes that a variable is not to be created on stack, but only once in global memory, and with a const
modifier and initialized with a compile-time constant, they can even be put away nicely into the read-only section.
This is commonly used for local definitions of arrays or strings:
static const int indices[] = {1, 3, 5, 7, ...};
for (int index : indices) {
// do something
}
static const char sqlCommand[] = "INSERT INTO ... some long statement ...";
if (!m_database.prepare(sqlCommand, ...)) {
m_log.error("Error preparing query: %s", sqlCommand);
// ...
}
If static wasn't there, the compiler would needlessly construct the array or string on the stack each time, value by value [1].
This is often used with lookup tables, repeated string constants (more manageable this way than macros), packet payloads etc. and the practical problem it solves is better performance and smaller code size.
[1] Almost, compilers are good at optimizing this stuff nowadays.
Upvotes: 2
Reputation: 28826
A simpler example would be a variable that counts how many times a function has been called:
void foo()
{
static int count;
// ...
count++;
// ...
}
Since it's declared static, it's initialized to zero only once, at program load time. This is different than
static int count = 0;
in which case it would be set to zero each time the function was called.
Upvotes: 0
Reputation: 206607
It allows you to create static data only once during the life of the process and use it through out the life of the process.
Example 1
Say you have a function that returns a long unit name given a short unit name. Given "m" as a unit, you would like to get back "meter". You can keep a map as a static variable in the function.
std::string const& getLongName(std::string const& shortName)
{
static std::map<std::string, std::string> unitsmap;
static std::string unknownUnit("Unknown Unit");
if ( unitsmap.empty() )
{
unitsmap["m"] = "meter";
unitsmap["cm"] = "centimeter";
unitsmap["mm"] = "millimeter";
unitsmap["g"] = "gram";
unitsmap["kg"] = "kilogram";
// etc.
}
std::map<std::string, std::stirng>::iterator f = unitsmap.find(shortName);
if ( f != unitsmap.end() )
{
return f->second;
}
else
{
return unknownUnit;
}
}
Example 2
The simple implementation of the Singleton Pattern can use a static variable in a function.
class Singleton
{
public:
static Singleton* instance()
{
static Singleton* theInstance = NULL;
if ( theInstance == NULL )
{
theInstance = new Singleton;
}
return theInstance;
}
private:
Singleton() {}
};
Upvotes: 1
Reputation: 145279
By declaring a static variable in a function, you
limit the variable's scope, and
delay dynamic initialization to the first time execution passes through the declaration.
In some cases the limited scope is most important, e.g. for a local constant.
In other cases the delayed dynamic initialization is the most important, e.g. for a Meyers' singleton.
One practical use case is to define a constant of arbitrary type with effectively external linkage (so that it won't be duplicated in each translation unit), in a header file, like
inline
auto get_t()
-> T const&
{
static T const the_t;
return the_t;
}
T const& t = get_t();
Here the reference takes up minimum space.
This can however also be done via the "templated constant" trick, or in C++11 via constexpr
, if applicable.
For comparison, here's the same as the above expressed with the "templated constant" trick (again, the purpose is to provide the extern linkage constant in a header file):
template< class Dummy >
struct The_t_constant
{
static T const value;
};
template< class Dummy >
T const The_t_constant<Dummy>::value;
T const& t = The_t_constant<void>::value;
Upvotes: 6
Reputation: 3095
A classic example is a delayed creation of a global instance of an object (not thread safe).
class Foo
{
// ...
static Foo* instance();
}
Foo* Foo::instance() {
static Foo *obj = nullptr;
if (obj == nullptr) {
obj = new Foo();
// ...
}
return obj;
}
Upvotes: 1
Reputation: 25505
The practical example is to create some default which is not a compile time constant. It also is better encapsulation because I don't expose the rest of my system to that static.
int DoSomething()
{
static foo * myFoo = new foo();//foos constructor may read from the environment or whatever else
//I only need it the first time I call DoSomething if I never call DoSomthing its never created
}
Upvotes: 0
Reputation: 18964
Imagine the function needs some value which is very expensive to compute, doesn't vary, and may never be needed at all. So you want to compute it, once, when it is first needed but not before.
Upvotes: 3