C ++本地静态变量分配

时间:2014-03-19 21:20:39

标签: c++

所以我目前正在学习C ++内存分配和静态变量。我知道局部变量被分配给堆栈,并且通常不是静态的好习惯。但是,是否存在使用本地静态变量根本不起作用的情况?

5 个答案:

答案 0 :(得分:0)

我认为你们两者之间存在混淆。

local variablelocal 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;
}

在这种情况下,你使用一个静态变量,它允许你在一个简单的递归函数中工作,并知道如果递归过多,它会调用自己太多次并中断(在这里退出)。

我的意思是“简单递归函数”是一个函数,它不能被调用多次以进行它需要做的计算。 (即如果它创建了一个重新调用该函数的对象,则深度参数将不会按预期工作,因为它会自动返回到零!)

然而,在大多数情况下,几乎总是避免使用静态局部变量,这样更容易也更安全。