As you may know, a local static variable cannot be accessed outside the function by name but can be accessed via pointer or reference to it. So the code below is well-formed.
But why? I know this fact as a fact, but have no ground. Actually what I want is the related excerpt from C++ standard. I'm reading it but not end up finding the evidence. Could anyone please give me the excerpt or a hint to find that (because just searching "static" in the document results in over a hundred of hits)?
#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"
}
I took a look at all of the about 20 questions suggested by stack overflow, but have no answer yet. (There was only one related question: Can I access static variables inside a function from outside.)
For the future readers (or just my note):
As indicated in the comment, the same applies to the case of a class member even if it is distant and 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"
}
The relevant quotes from the C++17 standard (n4659) tell us about the storage duration of static
variables:
6.7.1 Static storage duration [basic.stc.static]
1 All variables which do not have dynamic storage duration, do not have thread storage duration, and are not local have static storage duration. The storage for these entities shall last for the duration of the program (6.6.2, 6.6.4).
...
3 The keywordstatic
can be used to declare a local variable with static storage duration. [ Note: 9.7 describes the initialization of local static variables; 6.6.4 describes the destruction of local static variables. —end note ]
The lifetime of static
variables local to a function begins the first time the program flow encounters the declaration and it ends at program termination.
As mentioned in the comments there is no direct quote which says that such variables can be accessed via pointer or reference.
However the following quote from [basic.life]
(while not directly applicable to your scenario) tells something about using pointers to objects whose storage is still valid (allocated but not released or reused) but whose lifetime has not started or already ended:
6 Before the lifetime of an object has started but after the storage which the object will occupy has been allocated or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any pointer that represents the address of the storage location where the object will be or was located may be used but only in limited ways. For an object under construction or destruction, see 15.7. Otherwise, such a pointer refers to allocated storage, and using the pointer as if the pointer were of type
void*
, is well-defined. Indirection through such a pointer is permitted but the resulting lvalue may only be used in limited ways, as described below. The program has undefined behavior if:
(6.1) — the object will be or was of a class type with a non-trivial destructor and the pointer is used as the operand of a delete-expression,
(6.2) — the pointer is used to access a non-static data member or call a non-static member function of the object, or
(6.3) — the pointer is implicitly converted to a pointer to a virtual base class, or
(6.4) — the pointer is used as the operand of a static_cast, except when the conversion is to pointer tocv void
, or to pointer tocv void
and subsequently to pointer tocv char, cv unsigned char
, orcv std::byte
, or
(6.5) — the pointer is used as the operand of adynamic_cast
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With