代码之家  ›  专栏  ›  技术社区  ›  ynn

为什么可以从外部通过指针或引用访问静态本地对象?

  •  5
  • ynn  · 技术社区  · 7 年前

    您可能知道,局部静态变量不能通过名称在函数外部访问,但可以通过指针或对它的引用进行访问。因此,下面的代码格式良好。

    但是为什么呢?我知道这是事实,但没有根据。实际上我想要的是 C++标准的相关摘录

    #include <iostream>
    using namespace std;
    
    class Test {
    
        public:
    
            int * f(int i) const {
                static int j;
                j += i;
                cout << "now j = " << j << "\n";
                return &j;
            }
    
            int & g(int i) const { //same as above but handle reference
                static int k;
                k += i;
                cout << "now k = " << k << "\n";
                return k;
            }
    
    };
    
    int main() {
    
        Test t;
    
        int *p = t.f(3); //=> "now j = 3"
        *p += 10;
        t.f(0); //=> "now j = 13"
    
        int &r = t.g(3); //=> "now k = 3"
        r += 10;
        t.g(0); //=> "now k = 13"
    
    }
    

    我看了stack overflow提出的大约20个问题,但还并没有答案。(只有一个相关问题: Can I access static variables inside a function from outside .)


    如图所示: comment ,这同样适用于类成员的情况,即使它距离较远且 private .

    #include <iostream>
    using namespace std;
    
    class Base {
        private:
            int i = 0;
        public:
            int * return_pointer() { return &i; }
            void print() { cout << "i = " << i << "\n"; }
    };
    
    class Derived : public Base {
        public:
            int * return_pointer() { return Base::return_pointer(); }
    };
    
    int main() {
    
        Derived d;
        d.print(); //=> "i = 0"
    
        int *p = d.return_pointer();
        *p = 300;
        d.print(); //=> "i = 300"
    
    }
    
    0 回复  |  直到 7 年前
        1
  •  3
  •   P.W    7 年前

    C++17标准(n4659)中的相关引用告诉我们 static 变量:


    1所有没有动态存储持续时间、没有线程存储持续时间和非本地的变量都有静态存储持续时间。 这些实体的存储应在项目期间持续
    ...
    3.关键词 可用于声明具有静态存储持续时间的局部变量。[注:9.7描述了局部静态变量的初始化;6.6.4描述了局部静态变量的销毁。结束注]

    生命 静止的 函数的局部变量在程序流第一次遇到声明时开始,并在程序终止时结束。

    然而,以下引用自 [basic.life] (虽然不直接适用于您的场景)讲述了如何使用指向存储仍然有效(已分配但未释放或重新使用)但其生存期尚未开始或已结束的对象的指针:

    否则,这样的指针将引用已分配的存储,并将指针当作类型来使用 void* ,定义明确 . 允许通过此类指针进行间接寻址,但生成的左值只能以有限的方式使用,如下所述。在以下情况下,程序具有未定义的行为:
    (6.1)对象将是或曾经是具有非平凡析构函数的类类型,指针用作删除表达式的操作数,
    (6.2)指针用于访问非静态数据成员或调用对象的非静态成员函数,或

    cv void ,或指向 然后指向指向 cv char, cv unsigned char 或 cv std::byte
    dynamic_cast .