在函数中声明静态变量的实用性是什么? 我理解在函数中声明的静态变量的生命周期,但是我无法想象一个在函数中声明静态变量可能有用(或必要)的实际示例。你能给我一个应该以这种方式解决的问题的例子吗?
答案 0 :(得分:6)
通过在函数中声明静态变量,
限制变量的范围,
将动态初始化延迟到第一次执行时通过声明。
在某些情况下,有限的范围是最重要的,例如对于局部常数。
在其他情况下,延迟动态初始化是最重要的,例如,对于迈耶斯的单身人士。
一个实际用例是在头文件中定义具有有效外部链接的任意类型的常量(以便它不会在每个翻译单元中重复),例如
inline
auto get_t()
-> T const&
{
static T const the_t;
return the_t;
}
T const& t = get_t();
此处参考占用的空间最小。
然而,这也可以通过“模板化常量”技巧完成,或者通过constexpr
通过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;
完成,如果适用的话。
为了比较,这里与上面用“模板常量”技巧表达的相同(再次,目的是在头文件中提供extern链接常量):
{{1}}
答案 1 :(得分:3)
想象一下,这个功能需要一些价值,这个价值非常昂贵,不会变化,根本不需要。所以你想要计算它,一次,当它首次需要时,但不是之前。
答案 2 :(得分:2)
添加到其他答案,您还需要记住,在C ++中,static
关键字有很多含义。在函数体中,它还改变了不在堆栈上创建变量,但只在全局内存中创建一次,并且使用const
修饰符并使用编译时常量初始化,它们甚至可以被放置很好地进入只读部分。
这通常用于数组或字符串的本地定义:
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);
// ...
}
如果不存在static,编译器每次都会不必要地在堆栈上构造数组或字符串,值为值[1]。
这通常用于查找表,重复的字符串常量(比宏更容易管理),数据包有效负载等等,它解决的实际问题是更好的性能和更小的代码大小。
[1]几乎,编译器现在都善于优化这些东西。
答案 3 :(得分:1)
一个典型的例子是延迟创建对象的全局实例(而不是线程安全)。
class Foo
{
// ...
static Foo* instance();
}
Foo* Foo::instance() {
static Foo *obj = nullptr;
if (obj == nullptr) {
obj = new Foo();
// ...
}
return obj;
}
答案 4 :(得分:1)
它允许您在流程的整个生命周期中仅创建一次静态数据,并在整个流程的整个过程中使用它。
示例1
假设您有一个函数,该函数在给定短单位名称的情况下返回长单位名称。以“m”为单位,你想回到“米”。您可以将地图保留为函数中的静态变量。
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;
}
}
示例2
Singleton Pattern的简单实现可以在函数中使用静态变量。
class Singleton
{
public:
static Singleton* instance()
{
static Singleton* theInstance = NULL;
if ( theInstance == NULL )
{
theInstance = new Singleton;
}
return theInstance;
}
private:
Singleton() {}
};
答案 5 :(得分:0)
实际示例是创建一些不是编译时常量的默认值。它也是更好的封装,因为我没有将我的系统的其余部分暴露给那个静态。
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
}
答案 6 :(得分:0)
一个更简单的例子是一个计算函数被调用次数的变量:
void foo()
{
static int count;
// ...
count++;
// ...
}
由于它被声明为静态,因此在程序加载时它只被初始化为零一次。这与
不同static int count = 0;
在这种情况下,每次调用函数时都会将其设置为零。