This question already has answers here:
c++ access static members using null pointer
(5 answers)
Closed 8 years ago.
class Foo {
public:
static const int kType = 42;
};
void Func() {
Foo *bar = NULL;
int x = bar->kType;
putc(x, stderr);
}
Is this defined behavior? I read through the C++ standard but couldn't find anything about accessing a static const value like this... I've examined the assembly produced by GCC 4.2, Clang++, and Visual Studio 2010 and none of them perform a dereference of the NULL pointer, but I'd like to be sure.
You can use a pointer (or other expression) to access a static member; however, doing so through a NULL pointer unfortunately is officially undefined behavior. From 9.4/2 "Static members":
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.
Based on the example that follows:
class process {
public:
static void reschedule();
};
process& g();
void f()
{
process::reschedule(); // OK: no object necessary
g().reschedule(); // g() is called
}
The intent is to allow you to ensure that functions will be called in this scenario.
I believe that the actual value of the type is not used at all when calling
bar->kType
since kType is static, and bar is of type Foo it is the same as calling
Foo::kType
which you should really be doing anyway for clarity.
Calling bar->kType gives a compiler warning on most platforms for this reason.
Apart from the issue about accessing through the NULL pointer, there is another subtle issue in the code
$9.4.2/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."
$9.4.2/4- "If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a constant-initializer which shall be an integral constant expression (5.19). In that case, the member can appear in integral constant expressions. The member shall still be defined in a namespace scope if it is used in the program and the namespace scope definition shall not contain an initializer."
class Foo {
public:
static const int kType = 42;
};
int const Foo::kType;
void Func() {
Foo *bar = NULL;
int x = bar->kType;
putc(x, stderr);
}
So, yet one more reason for UB in the OP code.
Even if it worked it is awful code.
In serious programming you code not only for yourself, but also for others who will maintain your code.
Playing tricks like this must be avoided, because you respect your colleagues.
One consequence of this code: whether the pointer is NULL or not is even not at question, but it implies that this member kType may not be a plain non-static member of the class. Sometimes classes are big (this is evil too) and one cannot always recheck the definition of each and every variable.
Be rigorous. And call all your static members only this way:
Foo::kType
Another possibility is to follow a coding convention that let know that the member is static, for example, a s_ prefix for all classes static members:
Foo::s_kType
There is a higher rule so to speak which basically says - don't even think about compiling things that are provably not used. Advanced template programming depends on this a lot, so even if it might be a bit gray-zonish when a compiler clearly sees that the result of a construct is not used it's just going to eliminate it. Especially when it's provably safe like in this case.
You may want to try a few variants if you want - like making pointer a param of a function, result of a function, leaving a pointer uninitialized (best chance for triggering compiler complaint), doing a straight cast of 0 (best chance of being conplaint-free).
Related
For ordinary objects (even for const ones), it is permissible to end their lifetime by explicitly calling the destructor. Later, for example, the program can start another object lifetime in the same memory location using placement new.
But is it legal to call the destructor of a constexpr object? Can it result in some useful or at least well-formed program?
It is easy to imagine the opposite situation:
struct A{
int v = 0;
constexpr void foo() { v ? throw 1 : ++v; }
constexpr ~A() { foo(); }
};
constexpr A y;
int main() { y.~A(); y.~A(); }
This (most probably ill-formed) program is accepted by all compilers without any single warning: https://gcc.godbolt.org/z/aqMbfjxKT
And in Clang it finished by throwing an exception from constexpr destructor of A.
[dcl.constexpr] A constexpr specifier used in an object declaration declares the object as const.
You can do with such an object whatever you can do with any other const object. constexpr, apart from implying constness of the declared object, doesn't seem to affect anything about the object itself. It only affects static properties of the program, that is, which expressions are constant expressions, which template instantiations are valid, etc. There are no special provisions for run-time behaviour of objects declared with the constexpr specifier.
The Standard uses phrases similar to "constexpr object" a couple of times but it seems to be a misnomer. In my opinion it should have referred to constexpr variables instead. There should be no such thing as "constexpr objects" (like there are no inline objects), only constexpr variables (like there are inline variables). After all, constexpr is a decl-specifier, like inline. The objects that these variables refer to are just const.
Today I got a problem. I am in the need of a static member function, const is not a must but a better. But, I didn't succeed in my efforts. Can anybody say why or how?
When you apply the const qualifier to a nonstatic member function, it affects the this pointer. For a const-qualified member function of class C, the this pointer is of type C const*, whereas for a member function that is not const-qualified, the this pointer is of type C*.
A static member function does not have a this pointer (such a function is not called on a particular instance of a class), so const qualification of a static member function doesn't make any sense.
I agree with your question, but unfortunately the C++ is designed that way. For example:
class A {
int i; //<--- accessed with 'this'
static int s; //<---- accessed without 'this'
public:
static void foo () const // <-- imaginary const
{}
};
As of today, the const is considered in context of this. In a way, it's narrow. It can be made broader by applying this const beyond this pointer.
i.e. the "proposed" const, which may also apply to static functions, will restrict the static members from any modification.
In the example code, if foo() can be made const, then in that function, A::s cannot be modified. I can't see any language side effects, if this rule is added to standard. On the contrary, it's amusing that why such rule doesn't exist!
It is unfortunate that C++ doesn't accept it as per design but logically there are few use cases in which it validates well.
A function which is class level valid(static) might not change any static data, may be it will just query data should be const.
May be it should be like
if(Object)
MakeThisConstant()
else
MakeStaticDataConstant() // Only in the scope but static data cannot be constant so may be it should in some scenarios
Without getting into the details, it's because there may or may not be an object modified by the function, so const is ambiguous to the compiler.
Recall that const keeps objects constant, but there may or may not be an object here to keep constant.
A 'const member function' is not
allowed to modify the object it is called on, but static member
functions are not called on any object.
It is used directly by scope resolution operator.
Thus having a const static member function makes no sense, hence it is illegal.
While writing a custom reflection library I encountered a strange compiler behavior. However I was able to reproduce the problem with a much simplified code. Here is:
#include <iostream>
class OtherBase{};
class Base{};
/* Used only as a test class to verify if the reflection API works properly*/
class Derived : Base, OtherBase
{
public:
void Printer()
{
std::cout << "Derived::Printer() has been called" << std::endl;
}
};
/*Descriptor class that basically incapsulate the address of Derived::Printer method*/
struct ClassDescriptor
{
using type = Derived;
struct FuncDescriptor
{
static constexpr const auto member_address{ &type::Printer };
};
};
int main()
{
Derived derived;
auto address{ &Derived::Printer };
(derived.*address)(); // -> OK it compiles fine using the local variable address
(derived.*ClassDescriptor::FuncDescriptor::member_address)(); // -> BROKEN using the address from the descriptor class cause fatal error C1001 !
}
While trying debugging this problem I noticed that:
It happen only if Derived has multiple inheritance.
If I swap static constexpr const auto member_address{ &type::Printer } with inline static const auto member_address{ &type::Printer } it works.
Is it just a compiler bug, or I'm doing something wrong ?
Can I solve this problem while keeping the constexpr ?
Please note that I'm using MSVC 2017 with the compiler version 19.16.27024.1
All compiler options are default except for /std:c++17 enabled.
I know that updating (and surely i'll do it) the compiler version to the last one will probably solve the issue, but for now I would like to understand more about this problem.
About C1001, Microsoft Developer Network suggests that you remove some optimizations in your code: Fatal Error C1001. Once you've worked out which optimization is causing the issue, you can use a #pragma to disable that optimization in just that area:
// Disable the optimization
#pragma optimize( "", off )
...
// Re-enable any previous optimization
#pragma optimize( "", on )
Also, a fix for this issue has been released by Microsoft. You could install the most recent release.
const and constexpr:
const declares an object as constant. This implies a guarantee that once initialized, the value of that object won't change, and the compiler can make use of this fact for optimizations. It also helps prevent the programmer from writing code that modifies objects that were not meant to be modified after initialization.
constexpr declares an object as fit for use in what the Standard calls constant expressions. But note that constexpr is not the only way to do this.
When applied to functions the basic difference is this:
const can only be used for non-static member functions, not functions in general. It gives a guarantee that the member function does not modify any of the non-static data members.
constexpr can be used with both member and non-member functions, as well as constructors. It declares the function fit for use in constant expressions. The compiler will only accept it if the function meets certain criteria (7.1.5/3,4), most importantly:
The function body must be non-virtual and extremely simple: Apart from typedefs and static asserts, only a single return statement is allowed. In the case of a constructor, only an initialization list, typedefs, and static assert are allowed. (= default and = delete are allowed, too, though.)
As of C++14, the rules are more relaxed, what is allowed since then inside a constexpr function: asm declaration, a goto statement, a statement with a label other than case and default, try-block, the definition of a variable of non-literal type, definition of a variable of static or thread storage duration, the definition of a variable for which no initialization is performed.
The arguments and the return type must be literal types (i.e., generally speaking, very simple types, typically scalars or aggregates)
When can I / should I use both, const and constexpr together?
A. In object declarations. This is never necessary when both keywords refer to the same object to be declared. constexpr implies const.
constexpr const int N = 5;
is the same as
constexpr int N = 5;
However, note that there may be situations when the keywords each refer to different parts of the declaration:
static constexpr int N = 3;
int main()
{
constexpr const int *NP = &N;
}
Here, NP is declared as an address constant-expression, i.e. a pointer that is itself a constant expression. (This is possible when the address is generated by applying the address operator to a static/global constant expression.) Here, both constexpr and const are required: constexpr always refers to the expression being declared (here NP), while const refers to int (it declares a pointer-to-const). Removing the const would render the expression illegal (because (a) a pointer to a non-const object cannot be a constant expression, and (b) &N is in-fact a pointer-to-constant).
B. In member function declarations. In C++11, constexpr implies const, while in C++14 and C++17 that is not the case. A member function declared under C++11 as
constexpr void f();
needs to be declared as
constexpr void f() const;
under C++14 in order to still be usable as a const function.
You could refer to this link for more details.
Today I got a problem. I am in the need of a static member function, const is not a must but a better. But, I didn't succeed in my efforts. Can anybody say why or how?
When you apply the const qualifier to a nonstatic member function, it affects the this pointer. For a const-qualified member function of class C, the this pointer is of type C const*, whereas for a member function that is not const-qualified, the this pointer is of type C*.
A static member function does not have a this pointer (such a function is not called on a particular instance of a class), so const qualification of a static member function doesn't make any sense.
I agree with your question, but unfortunately the C++ is designed that way. For example:
class A {
int i; //<--- accessed with 'this'
static int s; //<---- accessed without 'this'
public:
static void foo () const // <-- imaginary const
{}
};
As of today, the const is considered in context of this. In a way, it's narrow. It can be made broader by applying this const beyond this pointer.
i.e. the "proposed" const, which may also apply to static functions, will restrict the static members from any modification.
In the example code, if foo() can be made const, then in that function, A::s cannot be modified. I can't see any language side effects, if this rule is added to standard. On the contrary, it's amusing that why such rule doesn't exist!
It is unfortunate that C++ doesn't accept it as per design but logically there are few use cases in which it validates well.
A function which is class level valid(static) might not change any static data, may be it will just query data should be const.
May be it should be like
if(Object)
MakeThisConstant()
else
MakeStaticDataConstant() // Only in the scope but static data cannot be constant so may be it should in some scenarios
Without getting into the details, it's because there may or may not be an object modified by the function, so const is ambiguous to the compiler.
Recall that const keeps objects constant, but there may or may not be an object here to keep constant.
A 'const member function' is not
allowed to modify the object it is called on, but static member
functions are not called on any object.
It is used directly by scope resolution operator.
Thus having a const static member function makes no sense, hence it is illegal.
This question already has answers here:
How to use a member variable as a default argument in C++?
(4 answers)
Closed 1 year ago.
struct X
{
X():mem(42){}
void f(int param = mem) //ERROR
{
//do something
}
private:
int mem;
};
Can anyone give me just one reason as to why this is illegal in C++?! That is to say, I know that it is an error, I know what the error means, I just can't understand why would this be illegal!
Your code (simplified):
struct X
{
int mem;
void f(int param = mem); //ERROR
};
You want to use a non-static member data as default value for a parameter of a member function. The first question which comes to mind is this : which specific instance of the class the default value mem belongs to?
X x1 = {100}; //mem = 100
X x2 = {200}; //mem = 200
x1.f(); //param is 100 or 200? or something else?
Your answer might be 100 as f() is invoked on the object x1 which has mem = 100. If so, then it requires the implementation to implement f() as:
void f(X* this, int param = this->mem);
which in turn requires the first argument to be initialized first before initialization of other argument. But the C++ standard doesn't specify any initialization order of the function arguments. Hence that isn't allowed. Its for the same reason that C++ Standard doesn't allow even this:
int f(int a, int b = a); //§8.3.6/9
In fact, §8.3.6/9 explicitly says,
Default arguments are evaluated each
time the function is called. The order
of evaluation of function arguments is
unspecified. Consequently, parameters
of a function shall not be used in
default argument expressions, even if
they are not evaluated.
And rest of the section is an interesting read.
An interesting topic related to "default" arguments (not related to this topic though):
Default argument in the middle of parameter list?
Default arguments have to be known at compile-time. When you talk about something like a function invocation, then the function is known at compile-time, even if the return value isn't, so the compiler can generate that code, but when you default to a member variable, the compiler doesn't know where to find that instance at compile-time, meaning that it would effectively have to pass a parameter (this) to find mem. Notice that you can't do something like void func(int i, int f = g(i)); and the two are effectively the same restriction.
I also think that this restriction is silly. But then, C++ is full of silly restrictions.
As DeadMG has mentioned above, somethig like
void func(int i, int f = g(i))
is illegal for the same reason. i suppose, however, that it is not simply a silly restriction. To allow such a construction, we need to restrict evaluation order for function parameters (as we need to calculate this before this->mem), but the c++ standard explicitly declines any assumptions on the evaluation order.
The accepted answer in the duplicate question is why, but the standard also explicitly states why this is so:
8.3.6/9:
"
Example: the declaration of X::mem1() in the following example is ill-formed because no object is supplied for the nonstatic member X::a used as an initializer.
int b;
class X
int a;
int mem1(int i = a); // error: nonstatic member a
// used as default argument
int mem2(int i = b); // OK: use X::b
static int b;
};
The declaration of X::mem2() is meaningful, however, since no object is needed to access the static member X::b. Classes, objects and members are described in clause 9.
"
... and since there exists no syntax to supply the object necessary to resolve the value of X::a at that point, it's effectively impossible to use non-static member variables as initializers for default arguments.
ISO C++ section 8.3.6/9
a nonstatic member shall not be used in a default argument expression, even if it
is not evaluated, unless it appears as the id-expression of a class member access expression (5.2.5) or unless it is used to form a pointer to member (5.3.1).
Also check out the example given in that section.
For one reason, because f is public, but mem is private. As such, code like this:
int main() {
X x;
x.f();
return 0;
}
...would involve outside code retrieving X's private data.
Aside from that, it would (or at least could) also make code generation a bit tricky. Normally, if the compiler is going to use a default argument, it gets the value it's going to pass as part of the function declaration. Generating code to pass that value as a parameter is trivial. When you might be passing a member of an object (possibly nested arbitrarily deeply) and then add in things like the possibility of it being a dependent name in a template, that might (for example) name another object with a conversion to the correct target type, and you have a recipe for making code generation pretty difficult. I don't know for sure, but I suspect somebody thought about things like that, and decided it was better to stay conservative, and possibly open thins up later, if a good reason was found to do so. Given the number of times I've seen problems arise from it, I'd guess it'll stay the way it is for a long time, simply because it rarely causes problems.
Compiler has to know addresses to maintain default values at compile time. Addresses of non-static member variables are unknown at compile time.
As all the other answers just discuss the problem, I thought I would post a solution.
As used in other languages without default arguments (Eg C# pre 4.0)
Simply use overloading to provide the same result:
struct X
{
X():mem(42){}
void f(int param)
{
//do something
}
void f()
{
f(mem);
}
private:
int mem;
};
Default arguments are evaluated in two distinct steps, in different contexts.
First, the name lookup for the default argument is performed in the context of the declaration.
Secondly, the evaluation of the default argument is performed in the context of the actual function call.
To keep the implementation from becoming overly complicated, some restrictions are applied to the expressions that can be used as default arguments.
Variables with non-static lifetime can't be used, because they might not exist at the time of the call.
Non-static member variables can't be used, because they need an (implicit) this-> qualification, which can typically not be evaluated at the call site.