所以我目前正在学习C ++内存分配和静态变量。我知道局部变量被分配给堆栈,并且通常不是静态的好习惯。但是,是否存在使用本地静态变量根本不起作用的情况?
答案 0 :(得分:0)
我认为你们两者之间存在混淆。
local variable
和local static variable
之间存在差异。前者的生命是直到function
退出(在堆栈中分配),在那里存在,直到你的program
退出(在程序存储器的Global/Static
区域中分配)
答案 1 :(得分:0)
本地静态变量将仅在第一次初始化。如果您有需要,我不认为使用本地静态变量有任何问题。
说,即使方法可以被多次调用,你也只需要发生一次特定的事情。
void foo()
{
static bool bFoo = false;
if (!bFoo)
{
Foo2();
// Do something only once.
bFoo = false;
}
}
foo();
foo();
多次调用该方法只会在第一次调用Foo2()方法而不是第二次。
答案 2 :(得分:0)
本地静态变量未在堆栈上分配,其生命周期是从您将其定义的范围输入到程序结束时。
有时它们用于延迟初始化对象或缓存结果。
答案 3 :(得分:0)
我对静态变量的最大问题是强制正确的初始化顺序。如果你有一个包含许多编译单元的非常大的项目,那么了解这个问题总是很好的。
此处有更多信息 - Static variables initialisation order。
答案 4 :(得分:0)
局部变量在堆栈上分配,因此每次进入函数时它们都是新的。这可以称为“可重入兼容”,因此可以用于多线程和递归函数而不用担心。
另一方面,静态变量有一个分配。因此,如果多次调用相同的函数,您将看到该变量的单个版本。这不被认为是可重入的,因为修改该值会产生可能不是您所期望的副作用。
关于多线程进程和本地静态变量的一个注意事项:第一次输入具有静态变量的函数时,在执行代码的任何指令之前,它会在您的脚下初始化。这意味着你完全无法保护代码不被多个线程执行。
所有这一切,你应该问自己:为什么我要使用静态变量?而不是相反(即为什么我不应该使用它)。有用的情况很少。在大多数其他情况下,它是无用的,应该避免以避免潜在的问题。
经常使用的地方是单例实例检索功能:
my_object *get_instance()
{
static my_object *singleton(NULL);
if(singleton == NULL)
{
singleton = new my_object;
}
return singleton;
}
这很有效,虽然坦率地说我在C ++中停止使用它。我现在将单例变量放在所谓的“静态”变量中,如:
namespace
{
my_object *singleton = NULL;
}
my_object *get_instance()
{
if(singleton == NULL)
{
singleton = new my_object;
}
return singleton;
}
这样做的原因是单例变量在启动时初始化,而不是第一次调用函数。进一步推动它,您可以将变量作为静态变量成员放在类中。据我所知,与无名称命名空间中的它没有任何不同。
重要说明:如果你创建一个(大)静态const局部数组,要知道第一次调用该函数时,它将在INTEL程序集中“手动”构建数组,如下所示:
lea pointer, %ecx
mov 12345678, %eax
mov %eax, (%ecx)
mov 12345678, %eax
mov %eax, (%ecx)
mov 12345678, %eax
mov %eax, (%ecx)
mov 12345678, %eax
mov %eax, (%ecx)
mov 12345678, %eax
mov %eax, (%ecx)
...
这将是缓慢的,可能是巨大的。将[static] const数组放入no name命名空间并使用该指针要好得多。然后,所有代码都会消失,并且您会在启动时从磁盘直接加载预先初始化的数组。 (显然,如果你在非静态局部变量中创建一个大型const数组,你将获得相同类型的代码,在这种情况下你会希望它是静态的,所以它只被初始化一次,但是你意识到你可以放它在您的无名称命名空间中,并且可以进一步优化!)
请注意,有些人提到递归函数是一个你可能不想要静态变量的地方。我现在给你一个案例,你可以使用它,避免“浪费”堆栈空间。但是,如果您打算使您的软件多线程,请不要使用它,因为在这种情况下它不起作用(不是没有一些额外的工作,正如我之前所说,在多线程环境中,您无法控制静态的初始化局部变量。)
int recursive(int value)
{
static int depth(0);
if(depth > 100)
{
std::cerr "too many recursive calls, dying!\n";
exit(1);
}
++depth;
[...]
if(special-case)
{
r = recursive(other_value);
[...]
}
[...]
--depth;
return result;
}
在这种情况下,你使用一个静态变量,它允许你在一个简单的递归函数中工作,并知道如果递归过多,它会调用自己太多次并中断(在这里退出)。
我的意思是“简单递归函数”是一个函数,它不能被调用多次以进行它需要做的计算。 (即如果它创建了一个重新调用该函数的对象,则深度参数将不会按预期工作,因为它会自动返回到零!)
然而,在大多数情况下,几乎总是避免使用静态局部变量,这样更容易也更安全。