I am working in embedded C++ project, where I plan to make memory statically allocated as much as I can. So, I am writing a set of functions to override new/delete for all classes and for the global new/delete.
Here is a naive implementation:
class MyClass
{
int x;
float y;
double z;
static MyClass m_preAllocatedObjects[100]; //Solution 1
static char m_preAllocatedMemory[100 * sizeof(MyClass)]; //Solution 2
static char* getPreAllocatedMemory() // Solution 3
{
static char localStaticMemory[100 * sizeof(MyClass)];
return localStaticMemory;
}
static void* operator new(size_t s){
void* p; /*fill p from the pre-allocated memory or object*/;
return p;
}
};
Solution 1: It works for object with default constructor only.
Solution 2: It gives compilation error use of undefined type 'MyClass'; and this is what I am asking about.
Solution 3: This solution works fine.
The question is:
Why can I create static members of MyClass, while I can't get sizeof(MyClass)?
while I can't get sizeof(MyClass)?
The reason is that MyClass is not fully defined until the closing } of the class definition, from section 9 Classes of the c++11 standard (draft n3337):
A class-name is inserted into the scope in which it is declared immediately after the class-name is seen.
The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name.
For purposes of access checking, the injected-class-name is treated as if it were a public member name. A
class-specifier is commonly referred to as a class definition. A class is considered defined after the closing
brace of its class-specifier has been seen even though its member functions are in general not yet defined.
The optional attribute-specifier-seq appertains to the class; the attributes in the attribute-specifier-seq are
thereafter considered attributes of the class whenever it is named.
and sizeof can only be applied to a complete type, from section 5.3.3 Sizeof:
The sizeof operator yields the number of bytes in the object representation of its operand. The operand is
either an expression, which is an unevaluated operand (Clause 5), or a parenthesized type-id. The sizeof
operator shall not be applied to an expression that has function or incomplete type, to an enumeration
type whose underlying type is not fixed before all its enumerators have been declared, to the parenthesized
name of such types, or to an lvalue that designates a bit-field. ...
To correct, define the size of the array outside of the class definition:
class MyClass
{
static char m_preAllocatedMemory[];
};
char MyClass::m_preAllocatedMemory[100 * sizeof(MyClass)];
To "know" the size of MyClass the compiler will need to know the whole class. When you are forward declaring a static MyClass m_preAllocatedObjects[100]; you are actually not defining the variable - to actually get the variable, you will have to do :
MyClass MyClasss::m_preAllocatedObjects[100];
somewhere in a .cpp file. This is where the memory for the objects are being "placed" as a lump in the data-segment. So the compiler doesn't have to know the actual size of MyClass at the point where you declare the variable. However, it does need to know the size to evaluate 100 * sizeof(MyClass).
You have to do that in two step:
declaring an array (without knowing its size) inside the class.
defining it, after you finish declaring the class, so that you know the size.
Here is the code:
class MyClass
{
int x;
...
static char m_preAllocatedMemory[];
};
char MyClass::m_preAllocatedMemory[100 * sizeof(MyClass)];
Related
Why can't I initialize non-const static member or static array in a class?
class A
{
static const int a = 3;
static int b = 3;
static const int c[2] = { 1, 2 };
static int d[2] = { 1, 2 };
};
int main()
{
A a;
return 0;
}
the compiler issues following errors:
g++ main.cpp
main.cpp:4:17: error: ISO C++ forbids in-class initialization of non-const static member ‘b’
main.cpp:5:26: error: a brace-enclosed initializer is not allowed here before ‘{’ token
main.cpp:5:33: error: invalid in-class initialization of static data member of non-integral type ‘const int [2]’
main.cpp:6:20: error: a brace-enclosed initializer is not allowed here before ‘{’ token
main.cpp:6:27: error: invalid in-class initialization of static data member of non-integral type ‘int [2]’
I have two questions:
Why can't I initialize static data members in class?
Why can't I initialize static arrays in class, even the const array?
Why I can't initialize static data members in class?
The C++ standard allows only static constant integral or enumeration types to be initialized inside the class. This is the reason a is allowed to be initialized while others are not.
Reference:
C++03 9.4.2 Static data members
§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.
What are integral types?
C++03 3.9.1 Fundamental types
§7
Types bool, char, wchar_t, and the signed and unsigned integer types are collectively called integral types.43) A synonym for integral type is integer type.
Footnote:
43) Therefore, enumerations (7.2) are not integral; however, enumerations can be promoted to int, unsigned int, long, or unsigned long, as specified in 4.5.
Workaround:
You could use the enum trick to initialize an array inside your class definition.
class A
{
static const int a = 3;
enum { arrsize = 2 };
static const int c[arrsize] = { 1, 2 };
};
Why does the Standard does not allow this?
Bjarne explains this aptly here:
A class is typically declared in a header file and a header file is typically included into many translation units. However, to avoid complicated linker rules, C++ requires that every object has a unique definition. That rule would be broken if C++ allowed in-class definition of entities that needed to be stored in memory as objects.
Why are only static const integral types & enums allowed In-class Initialization?
The answer is hidden in Bjarne's quote read it closely,
"C++ requires that every object has a unique definition. That rule would be broken if C++ allowed in-class definition of entities that needed to be stored in memory as objects."
Note that only static const integers can be treated as compile time constants. The compiler knows that the integer value will not change anytime and hence it can apply its own magic and apply optimizations, the compiler simply inlines such class members i.e, they are not stored in memory anymore, As the need of being stored in memory is removed, it gives such variables the exception to rule mentioned by Bjarne.
It is noteworthy to note here that even if static const integral values can have In-Class Initialization, taking address of such variables is not allowed. One can take the address of a static member if (and only if) it has an out-of-class definition.This further validates the reasoning above.
enums are allowed this because values of an enumerated type can be used where ints are expected.see citation above
How does this change in C++11?
C++11 relaxes the restriction to certain extent.
C++11 9.4.2 Static data members
§3
If a static data member is of const literal type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both these cases, the member may appear in constant expressions. —end note ] 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.
Also, C++11 will allow(§12.6.2.8) a non-static data member to be initialized where it is declared(in its class). This will mean much easy user semantics.
Note that these features have not yet been implemented in latest gcc 4.7, So you might still get compilation errors.
This seems a relict from the old days of simple linkers. You can use static variables in static methods as workaround:
// header.hxx
#include <vector>
class Class {
public:
static std::vector<int> & replacement_for_initialized_static_non_const_variable() {
static std::vector<int> Static {42, 0, 1900, 1998};
return Static;
}
};
int compilation_unit_a();
and
// compilation_unit_a.cxx
#include "header.hxx"
int compilation_unit_a() {
return Class::replacement_for_initialized_static_non_const_variable()[1]++;
}
and
// main.cxx
#include "header.hxx"
#include <iostream>
int main() {
std::cout
<< compilation_unit_a()
<< Class::replacement_for_initialized_static_non_const_variable()[1]++
<< compilation_unit_a()
<< Class::replacement_for_initialized_static_non_const_variable()[1]++
<< std::endl;
}
build:
g++ -std=gnu++0x -save-temps=obj -c compilation_unit_a.cxx
g++ -std=gnu++0x -o main main.cxx compilation_unit_a.o
run:
./main
The fact that this works (consistently, even if the class definition is included in different compilation units), shows that the linker today (gcc 4.9.2) is actually smart enough.
Funny: Prints 0123 on arm and 3210 on x86.
It's because there can only be one definition of A::a that all the translation units use.
If you performed static int a = 3; in a class in a header included in all a translation units then you'd get multiple definitions. Therefore, non out-of-line definition of a static is forcibly made a compiler error.
Using static inline or static const remedies this. static inline only concretises the symbol if it is used in the translation unit and ensures the linker only selects and leaves one copy if it's defined in multiple translation units due to it being in a comdat group. const at file scope makes the compiler never emit a symbol because it's always substituted immediately in the code unless extern is used, which is not permitted in a class.
One thing to note is static inline int b; is treated as a definition whereas static const int b or static const A b; are still treated as a declaration and must be defined out-of-line if you don't define it inside the class. Interestingly static constexpr A b; is treated as a definition, whereas static constexpr int b; is an error and must have an initialiser (this is because they now become definitions and like any const/constexpr definition at file scope, they require an initialiser which an int doesn't have but a class type does because it has an implicit = A() when it is a definition -- clang allows this but gcc requires you to explicitly initialise or it is an error. This is not a problem with inline instead). static const A b = A(); is not allowed and must be constexpr or inline in order to permit an initialiser for a static object with class type i.e to make a static member of class type more than a declaration. So yes in certain situations A a; is not the same as explicitly initialising A a = A(); (the former can be a declaration but if only a declaration is allowed for that type then the latter is an error. The latter can only be used on a definition. constexpr makes it a definition). If you use constexpr and specify a default constructor then the constructor will need to be constexpr
#include<iostream>
struct A
{
int b =2;
mutable int c = 3; //if this member is included in the class then const A will have a full .data symbol emitted for it on -O0 and so will B because it contains A.
static const int a = 3;
};
struct B {
A b;
static constexpr A c; //needs to be constexpr or inline and doesn't emit a symbol for A a mutable member on any optimisation level
};
const A a;
const B b;
int main()
{
std::cout << a.b << b.b.b;
return 0;
}
A static member is an outright file scope declaration extern int A::a; (which can only be made in the class and out of line definitions must refer to a static member in a class and must be definitions and cannot contain extern) whereas a non-static member is part of the complete type definition of a class and have the same rules as file scope declarations without extern. They are implicitly definitions. So int i[]; int i[5]; is a redefinition whereas static int i[]; int A::i[5]; isn't but unlike 2 externs, the compiler will still detect a duplicate member if you do static int i[]; static int i[5]; in the class.
I think it's to prevent you from mixing declarations and definitions. (Think about the problems that could occur if you include the file in multiple places.)
static variables are specific to a class . Constructors initialize attributes ESPECIALY for an instance.
I am working on some code where there is a simple enum in a class. A different piece of code has a pointer to that class and is accessing a value of the enum through the arrow pointer.
How on earth is the class able to access MY_VALUE1 this way?
I though it would only allow access via MyClass::MY_VALUE1 or MyClass::MyEnum::MY_VALUE1.
class MyClass {
public:
enum MyEnum{
MY_VALUE0 = 0,
MY_VALUE1 = 1
};
//getters, setters as appropriate
};
//Other class
MyClass* myClass = new MyClass();
//Compiles without C++11
if(getRandomEnum() == myClass->MY_VALUE1)
{
//Do Stuff
}
The -> operator is (mostly) an abbreviation for dereference (*) and selection (.). In other words, a->b is the same as (*(a)).b. (§5.2.5/2; See notes below).
The . syntax is class member access, as defined by §5.2.5 [expr.ref]; the identifier on the right-hand side of the . can be a static or non-static data member, function, or member enumerator (paragraph 4 of the cited section). It cannot be a nested type. In this sense, member enumerators are syntactically similar to static const data members.
Notes:
As §13.5.6 clarifies, a->b is is subject to operator overloading. If a is not a pointer type, then -> may be overloaded, in which case the expression is interpreted as (a.operator->())->b. Eventually, the sequence of overloaded -> calls must result in a pointer type, at which point the interpretation of §5.2.5/2 is applied.
An important difference between Class::member and value.member is that in the second case, value will be evaluated even if that is unnecessary to resolve the value of member.
From C++ ISO/IEC 2011
An enumerator declared in class scope can be referred to using the
class member access operators (::, . (dot) and -> (arrow)),
The enum values are treated much as if they were static members
of the class, and can be accessed in two ways: via the class
name followed by the scope resolution operator
(MyClass::MY_VALUE0), or like any other member
(instance.MY_VALUE0 or pointer->MY_VALUE0).
Note that in the latter case, the operand on the left is still
evaluated, even though the results of the evaluation is not
used. In other words, if I write f()->MY_VALUE0 (where f()
returns a MyClass*), the function will be called, despite the
fact that its return value is not used.
For example, let's consider the static storage class specifier. Here are a few examples of both valid and ill-formed uses of this storage class specifier:
static int a; // valid
int static b; // valid
static int* c; // valid
int static* d; // valid
int* static e; // ill-formed
static int const* f; // valid
int static const* g; // valid
int const static* h; // valid
int const* static i; // ill-formed
typedef int* pointer;
static pointer j; // valid
pointer static k; // valid
(The declarations marked "valid" were accepted by Visual C++ 2012, g++ 4.7.2, and Clang++ 3.1. The declarations marked "ill-formed" were rejected by all of those compilers.)
This seems odd because the storage class specifier applies to the declared variable. It is the declared variable that is static, not the type of the declared variable. Why are e and i ill-formed, but k is well-formed?
What are the rules that govern valid placement of storage class specifiers? While I've used static in this example, the question applies to all storage class specifiers. Preferably, a complete answer should cite relevant sections of the C++11 language standard and explain them.
In summary, anywhere in the declaration specifier (See section 7.1 in the ISO/IEC 14882-2012), ie before the *. Qualifiers after the * are associated with the pointer declarator, not the type specifier, and static doesn't make sense within the context of a pointer declarator.
Consider the following cases:
You can declare a normal int and a pointer to an int in the same declaration list, like this:
int a, *b;
this is because the type specifier is int, then you have two declarations using that type specifier int, a, and a pointer declarator *a which declares a pointer to int. Now consider:
int a, static b; // error
int a, *static b; // error
int a, static *b; // error
which should look wrong (as they are), and the reason (as defined in sections 7.1 and 8.1) is because C and C++ require that your storage specifiers go with your type specifier, not in your declarator.
So now it should be clear that that the following is also wrong, since the above three are also wrong:
int *static a; // error
Your last example,
typedef int* pointer;
static pointer j; // valid
pointer static k; // valid
are both valid and both equivalent because the pointer type is defined as a type specifier and you can put your type specifier and storage specifeir in any order. Note that they are both equivalent and would be equivalent to saying
static int *j;
static int *k;
or
int static *j;
int static *k;
Per 7.1, the [simplified] structure of C++ declaration is
decl-specifier-seq init-declarator-list;
Per 7.1/1, storage class specifiers belong in the initial "common" part decl-specifier-seq.
Per 8/1, init-declarator-list is a sequence of declarators.
Per 8/4, the * part of pointer declaration is a part of an individual declarator in that sequence. This immediately means that everything that follows a * is a part of that individual declarator. This is why some of your storage class specifier placements are invalid. Declarator syntax does not allow inclusion of storage class specifiers.
The rationale is rather obvious: since storage class specifiers are supposed to apply to all declarators in the whole declaration, they are placed into the "common" part of the declaration.
I'd say that a more interesting (and somewhat related) situation takes place with specifiers that can be present in both decl-specifier-seq and individual declarators, like const specifier. For example, in the following declaration
int const *a, *b;
does const apply to all declarators or only to the first one? The grammar dictates the former interpretation: that const applies to all declarators, i.e. it is a part of the decl-specifier-seq.
If you employ the "Golden Rule" (which also doesn't apply only to pointers) it follows naturally, intuitively, and it avoids a lot of mistakes and pitfalls when declaring variables in C/C++. The "Golden Rule" should not be violated (there are rare exceptions, like const applied to array typedefs, which propagates const to the base type, and references, that came with C++).
K&R, Appendix A, Section 8.4, Meaning of Declarators states:
Each declarator is taken to be an assertion that when a construction of the same form as the declarator appears in an expression, it yields an object of the indicated type and storage class.
To declare a variable in C/C++ you should really think of the expression you should apply to it to get the base type.
1) There should be a variable name
2) Then comes the expression as valid* out of the declaration statement, applied to the variable name
3) Then comes the remaining information and properties of declaration like base type and storage
Storage is not a characteristic you can always confer to the outcome of expressions, contrary to constness for example. It makes sense only at declaration. So storage must come somewhere else that's not in 2.
int * const *pp;
/*valid*/
int * static *pp;
/*invalid, this clearly shows how storage makes no sense for 2 and so breaks */
/*the golden rule. */
/*It's not a piece of information that goes well in the middle of a expression.*/
/*Neither it's a constraint the way const is, it just tells the storage of */
/*what's being declared. */
I think K&R wanted us to use inverted reasoning when declaring variables, it's frequently not the common habit. When used, it avoids most of complex declaration mistakes and difficulties.
*valid is not in a strict sense, as some variations occur, like x[], x[size, not indexing], constness, etc... So 2 is a expression that maps well (for the declaration usage), "same form", one that reflects variable's use, but not strictly.
Golden Rule Bonus for the Uninitiated
#include <iostream>
int (&f())[3] {
static int m[3] = {1, 2, 3};
return m;
}
int main() {
for(int i = 0; i < sizeof(f()) / sizeof(f()[0]); ++i)
std::cout << f()[i] << std::endl;
return 0;
}
In the context of declarations, & is not an operation to get an address, it just tells what's a reference.
f(): f is a function
&return: its return is a reference
reference[3]: the reference is to an array of 3 elements
int array[i]: an element is an int
So you have a function that returns a reference to an array of 3 integers, and as we have the proper compile time information of the array size, we can check it with sizeof anytime =)
Final golden tip, for anything that can be placed before the type, when in multiple declarations, it's to be applied to all the variables at once, and so can't be applied individually.
This const can't be put before int:
int * const p;
So the following is valid:
int * const p1, * const p2;
This one can:
int const *p; // or const int *p;
So the following is invalid:
int const *p1, const *p2;
The exchangeable const is to be applied for all:
int const *p1, *p2; // or const int *p1, *p2;
Declaration Conventions
Because of that, I always put everything that can't be put before the type, closer to the variable (int *a, int &b), and anything that can be put before, I put before (volatile int c).
There's much more on this topic at http://nosubstance.me/post/constant-bikeshedding/.
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).
My understanding is that C++ allows static const members to be defined inside a class so long as it's an integer type.
Why, then, does the following code give me a linker error?
#include <algorithm>
#include <iostream>
class test
{
public:
static const int N = 10;
};
int main()
{
std::cout << test::N << "\n";
std::min(9, test::N);
}
The error I get is:
test.cpp:(.text+0x130): undefined reference to `test::N'
collect2: ld returned 1 exit status
Interestingly, if I comment out the call to std::min, the code compiles and links just fine (even though test::N is also referenced on the previous line).
Any idea as to what's going on?
My compiler is gcc 4.4 on Linux.
My understanding is that C++ allows static const members to be defined inside a class so long as it's an integer type.
You are sort of correct. You are allowed to initialize static const integrals in the class declaration but that is not a definition.
Interestingly, if I comment out the call to std::min, the code compiles and links just fine (even though test::N is also referenced on the previous line).
Any idea as to what's going on?
std::min takes its parameters by const reference. If it took them by value you'd not have this problem but since you need a reference you also need a definition.
Here's chapter/verse:
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.
See Chu's answer for a possible workaround.
Bjarne Stroustrup's example in his C++ FAQ suggests you are correct, and only need a definition if you take the address.
class AE {
// ...
public:
static const int c6 = 7;
static const int c7 = 31;
};
const int AE::c7; // definition
int f()
{
const int* p1 = &AE::c6; // error: c6 not an lvalue
const int* p2 = &AE::c7; // ok
// ...
}
He says "You can take the address of a static member if (and only if) it has an out-of-class definition". Which suggests it would work otherwise. Maybe your min function invokes addresses somehow behind the scenes.
Another way to do this, for integer types anyway, is to define constants as enums in the class:
class test
{
public:
enum { N = 10 };
};
Not just int's. But you can't define the value in the class declaration. If you have:
class classname
{
public:
static int const N;
}
in the .h file then you must have:
int const classname::N = 10;
in the .cpp file.
Here's another way to work around the problem:
std::min(9, int(test::N));
(I think Crazy Eddie's answer correctly describes why the problem exists.)
As of C++11 you can use:
static constexpr int N = 10;
This theoretically still requires you to define the constant in a .cpp file, but as long as you don't take the address of N it is very unlikely that any compiler implementation will produce an error ;).
C++ allows static const members to be defined inside a class
Nope, 3.1 §2 says:
A declaration is a definition unless it declares a function without specifying the function's body (8.4), it contains the extern specifier (7.1.1) or a linkage-specification (7.5) and neither an initializer nor a functionbody, it declares a static data member in a class definition (9.4), it is a class name declaration (9.1), it is an opaque-enum-declaration (7.2), or it is a typedef declaration (7.1.3), a using-declaration (7.3.3), or a using-directive (7.3.4).