C++ static class member with private constructor - c++

Why can a private constructor be used in this case? I can't explain it to myself. In this case, I initialize the class field (the type of which is the same class) from the outside, since it is static.
Edit1:
I use C++ 17 (gcc 11.2).
#include <iostream>
using namespace std;
class MainMenu {
public:
MainMenu(const MainMenu& other) = delete;
MainMenu& operator=(const MainMenu& other) = delete;
static MainMenu& GetInstance() { return _instance; }
private:
static MainMenu _instance;
MainMenu() { cout << __PRETTY_FUNCTION__ << endl;}
};
// HERE HERE HERE!!
MainMenu MainMenu::_instance = MainMenu(); // Or just MainMenu MainMenu::_instance;
int main() {
MainMenu::GetInstance();
return 0;
}
Result:
MainMenu::MainMenu()
Process finished with exit code 0

I would use the following mental model for it:
a. Note that your are instantiating the variable (it would have an incomplete type at the class's scope, so it cannot be inline withing the class's scope), not actually (re)assigning it
b. it is already declared global/static on class's scope so technically the constructor is called within the class. That's fine, even with the constructor being private, because it's called from exactly that privately accessible scope. True, the definition outside looks off, but that does not matter, as the declaration specifies its scope.
Excerpt from C++17 standard:
12.2.3.2 Static data members [class.static.data]
2 The declaration of a non-inline static data member in its class definition is not a
definition and may be of an incomplete type other than cv void. The
definition for a static data member that is not defined inline in the
class definition shall appear in a namespace scope enclosing the
member’s class definition. In the definition at namespace scope, the
name of the static data member shall be qualified by its class name
using the :: operator. The initializer expression in the definition of
a static data member is in the scope of its class (6.3.7)
And the example is your case exactly:
class process {
static process* run_chain;
static process* running;
};
process* process::running = get_main();
process* process::run_chain = running;
Any additional citations from the C++ standard to explain it in a better way are most welcome. :)

Related

Definition of the static data member

I'm reading Scott Meyers' C++ and come across this example:
class GamePlayer{
private:
static const int NumTurns = 5;
int scores[NumTurns];
// ...
};
What you see above is a declaration for NumTurns, not a definition.
Why not a definition? It looks like we initialize the static data member with 5.
I just don't understand what it means to declare but not define a variable with the value 5. We can take the address of the variable fine.
class A
{
public:
void foo(){ const int * p = &a; }
private:
static const int a = 1;
};
int main ()
{
A a;
a.foo();
}
DEMO
Because it isn't a definition. Static data members must be defined outside the class definition.
[class.static.data] / 2
The declaration of a static data member in its class definition is not
a definition and may be of an incomplete type other than cv-qualified
void. The definition for a static data member shall appear in a
namespace scope enclosing the member’s class definition.
As for taking the address of your static member without actually defining it, it will compile, but it shouldn't link.
you need to put a definition of NumTurns in source file, like
const int GamePlayer::NumTurns;

C++ lambda friendship

When a lambda function is declared inside a function F which is a friend of class C, does the lambda function have access to C private members? Specifically, does the standard allow it?
C++11 §[expr.prim.lambda] 5.1.2/3:
The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type — called the closure type — whose properties are described below. This class type is not an aggregate (8.5.1). The closure type is declared in the smallest block scope, class scope, or namespace scope that contains the corresponding lambda-expression. ...
Since the closure type is declared within the friend function, it will have the same access per §[class.local] 9.8/1:
A class can be declared within a function definition; such a class is called a local class. The name of a local class is local to its enclosing scope. The local class is in the scope of the enclosing scope, and has the same access to names outside the function as does the enclosing function. ...
A nested class automatically has access to all the members its "owner" has access to. You don't need lambdas to see this:
class A {
friend struct B;
friend void g();
static void f() { }
};
struct B {
struct C {
static void f() { A::f(); }
};
static void f() { C::f(); }
};
void g() {
struct D {
static void f() { A::f(); }
};
D::f();
}
Despite not being listed explicitly as friends, C::f and D::f can call the private A::f without any complaints from the compiler.
Lambdas are implemented using compiler-generated local classes (that's not just an implementation detail, that's what the standard requires), so the same rules as for other local classes apply.
The rule that local classes can access the same members is spelled out in the standard in 9.8:
The local class is in the scope of the enclosing scope, and has the same access to names outside the function as does the enclosing function.

Which function is used to initialize the static class member?

I have a question about which function is chosen to init a static class member.
//Base.h
class Base
{
private:
static int count;
static int countInit()
{
return 10;
}
public:
Base()
{
}
};
//and Base.cpp
static int countInit()
{
return 0;
}
int Base::count=countInit();//member function is used.
static int local_count=countInit();//the local one in Base.cpp
The variable Base::count is initialized with Base::countInit() rather than the countInit() defined in Base.cpp. But the local_count is initialized by the local countInit. So, I wonder, is there a rule like Koenig lookup within this case?
After you write int Base::count you are in class Base, so static function of class will be called. Unqualified lookup will be used here
from 3.4.2/13
A name used in the definition of a static data member of class X (9.4.2) (after the qualified-id of the static
member) is looked up as if the name was used in a member function of X.
from 9.4.2
The definition for a static data member shall appear in a namespace
scope enclosing the member’s class definition. In the definition at namespace scope, the name of the static
data member shall be qualified by its class name using the :: operator. The initializer expression in the
definition of a static data member is in the scope of its class
Example:
class process {
static process* run_chain;
static process* running;
};
process* process::running = get_main();
process* process::run_chain = running;

static keyword inside a class and outside it

The static keyword is related to internal linkage generally, but the static keyword used inside a class has external linkage right? The variables m, n below are accessible outside the class file.
class c {
int i;
int j;
static int m;
static int n;
public:
void zap();
static void clear();
};
Right.
The keyword static is heavily overloaded with too many different meanings:
On a variable or function at namespace scope it gives the name internal linkage.
On a class member it makes it a static member, which doesn't affect linkage.
On a variable at function scope it gives the variable "static storage duration" as opposed to "automatic" or "dynamic" storage duration (i.e. the variable's lifetime extends to the end of the program, like global variables.)
As I stated in my comment, static members are those associated only with the class rather than individual objects.
static members belong to the class; for variables, they're accessible without an object and shared amongst instances e.g.
struct Foo {
static void *bar;
static void *fu();
}
so Foo::bar and Foo::fu are legal.
They are introduced in §9.4 of the C++03 standard;
A data or function member of a class may be declared static in a class definition, in which case it is a static member of the class.
A static member s of class X may be referred to using the qualified-id expression X::s; it is not necessary to use the class member access syntax (5.2.5) to refer to a static member. A static member may be referred to using the class member access syntax, in which case the object-expression is evaluated
class process {
public:
static void reschedule();
};
process& g();
void f()
{
process::reschedule(); // OK: no object necessary
g().reschedule(); // g() is called
}
A static member may be referred to directly in the scope of its class or in the scope of a class derived (clause 10) from its class; in this case, the static member is referred to as if a qualified-id expression was used, with the nested-name-specifier of the qualified-id naming the class scope from which the static member is referenced.
int g();
struct X {
static int g();
};
struct Y : X {
static int i;
};
int Y::i = g(); // equivalent to Y::g();
...
You could say that static members are members of the class and not any specific object instance. That is, they have the same value for all object instances.
Static member functions, while not having a value, are otherwise the same. Instead of being unique for each object instance, they can be seen as part of the class. This means that they have no this pointer and can not access non-static member variables.

Why can I call the private constructor from ?global scope?

this code compiles and runs without errors:
class foo{
static foo *ref;
foo(){}
public:
static foo *getRef(){
return ref;
}
void bar(){}
};
foo* foo::ref = new foo; // the construcrtor is private!
int main(int argc, const char *argv[])
{
foo* f = foo::getRef();
f->bar();
return 0;
}
could somebody explain why can the constructor be called?
That scope isn't global - static members are at class scope, and so their initialization expression is also at class scope.
The answer is that it is not available in the global scope. The initializer of a static member is defined to be inside the class scope, so it has access to the private members.
§9.4.2/2 [...]The initializer expression in the definition of a static data member is in the scope of its class (3.3.6).
This form of initialization of static members are not necessary in older c++. They are made compulsary in later release of c++.
And, this form of static member initialization will generally used to initialize the static members before creation of any class objects.
(E.g) int MyClass::objectsCounter=0;
But by,
foo* foo::ref = new foo;
this statement you are just initializing a static member (which is of pointer type) by creating a new object.
And in this case you are intializing a private member by calling a private method of its own class.
Hence there is no role of globe scope here.