C++ 实例方法中的静态变量

C++ 实例方法中的静态变量,c++,static-variables,instance-methods,C++,Static Variables,Instance Methods,假设我有一个程序: class Foo { public: unsigned int bar () { static unsigned int counter = 0; return counter++; } }; int main () { Foo a; Foo b; } (当然,这个例子毫无意义,因为我显然将“counter”声明为私有属性,但它只是为了说明问题) 我想知道C++在这种情况下的行为:BAR()方法中的变量“

假设我有一个程序:

class Foo {
 public:
    unsigned int bar () {
        static unsigned int counter = 0;
        return counter++;
    }
};

int main ()
{
    Foo a;
    Foo b;
}
(当然,这个例子毫无意义,因为我显然将“counter”声明为私有属性,但它只是为了说明问题)

我想知道C++在这种情况下的行为:BAR()方法中的变量“计数器”对于每个实例是否相同?

< P>“每个实例都相同”,您的意思是在每个类实例中共享这个变量的一个实例,那么,是的,这是正确的。该类的所有实例都将使用相同的变量实例


但请记住,对于类变量,在许多情况下必须考虑多线程之类的问题,这是一个完全不同的主题。

是的,
计数器将在可执行文件中
Foo
类型的对象的所有实例中共享。只要您处于单线程环境中,它就可以作为共享计数器正常工作

在多线程环境中,您将有一些有趣的竞赛条件要调试:(第二)从C++编程语言(200版),Bjarne Stroustrup:

除了在[普通]函数(§7.1.2)和类(§10.2.4)内,不要使用静态


你只需要掌握两件事:

  • 静态变量存储在执行程序的静态区域(与全局变量的静态区域相同)
  • 范围受括号的一般规则限制。此外,静态变量具有内部链接

  • 您的示例离您可以编译和测试的内容还有几行:

    #include <iostream>
    using namespace std;
    class Foo {
     public:
        unsigned int bar () {
            static unsigned int counter = 0;
            return counter++;
        }
    };
    
    int main ()
    {
        Foo a;
        Foo b;
    
        for (int i=0; i < 10; i++)
          cout<<i<<". "<<a.bar()<<" / "<<b.bar()<<endl;
    }
    

    因此,是的,计数器在所有实例中共享。

    假设编译器尚未为您处理此问题。语言定义是,变量在方法的所有调用中都是一致的。因此,这是编译器的任务,因此在多线程语言(下一版本的C++)中,这是编译器的任务。在此版本中,它取决于编译器与线程库的集成。gcc已经涵盖了这一点,并保证跨多个线程访问静态变量是安全的。@Martin York:也就是说,C++0x中的静态变量保证是线程本地的?多么有趣,可能会让一些人大吃一惊。就像一个漂亮的静态类实例计数器。突然之间,您将计算每个线程的实例。我不敢相信他们会做出这样的改变。你确定?!真正地这可能会破坏大量的代码。我无法想象委员会能收支平衡。001%的现有代码。@Omnifarious:你到底是怎么从我的声明中得到的!!这将是一个使用符号的完全改变。我相信你一定是疯了才想出那种解释。不,编译器(在语言级别)必须保证变量的符号。如果语言是多线程的,那么它必须保证对varibale的访问是线程安全的(即原子的。在一个线程中int的增量必须在另一个线程中立即可用)。目前,gcc已经保证了这一点。注意:这并不意味着需要保证对方法的访问是线程安全的。但这确实意味着不能基于每个处理器缓存状态。注2:此保证仅在语言具有内置线程的概念时可用(C++没有,但C++0x会)。生命周期不是程序的生命周期。从第一次使用(可能永远不会)到销毁(与创建静态变量的顺序相反)。Alos note初始化很好,因为它是函数的一部分,而不是类的一部分。@niel。。我的错!!我没有看到最后一句是关于命名空间范围静态变量的。局部静态变量(如问题中的变量)没有链接。(无法引用来自不同作用域的局部变量。如何引用在main中定义的变量?
    main()::v
    不起作用)。规则非常棒。但只有在正确的上下文中使用。nieve用户可以将报价提交给hart。如果你要引用这样的话,你必须包含完整的上下文。有趣的是,你的输出是一个完美的例子,说明了序列点和执行顺序是如何工作的,并且可能导致违反直觉的结果。
    0. 1 / 0
    1. 3 / 2
    2. 5 / 4
    3. 7 / 6
    4. 9 / 8
    5. 11 / 10
    6. 13 / 12
    7. 15 / 14
    8. 17 / 16
    9. 19 / 18