I am a little bit confused ...
Why is this allowed in C++:
static int t = 0;
class A
{
public:
A() : m(t++)
{
cout << "C:" << m << endl;
if(t >= 5)
{
A a; // <<<< ----- THIS line
throw( a);
}
}
int m;
};
But this not:
static int t = 0;
class A
{
public:
A() : m(t++)
{
cout << "C:" << m << endl;
}
A a; // <<<< ----- THIS line
int m;
};
The second one is not compiling as expected (yes, I know why it's not compiling: at that point in code the A is still incomplete) ...
But ... the first one compiles nicely (and does what it's supposed to do, ie: crashes the application on a statement like: A a[10]; ). Is the A a complete type in the constructor? Can also point me some C++ standard entries for this situation?
When you are declaring any variable, compiler should know the size of that. in case of your second example you are creating an object of A inside A so compiler will not be able to calculate the size of A to allocate memory.
Can also point me some C++ standard entries for this situation?
Yes, the draft C++ standard says a class is not completely defined until the closing }, this is in section 9.2 Class members paragraph 2:
A class is considered a completely-defined object type (3.9) (or complete type) at the closing } of the classspecifier. [...]
and all non-static data members of a class must be complete, from paragraph 9:
Non-static (9.4) data members shall not have incomplete types. In particular, a class C shall not contain a non-static member of class C, but it can contain a pointer or reference to an object of class C.
but it is considered complete within the constructor also within paragraph 2:
[...]Within the class member-specification, the class is regarded as complete within function bodies, default arguments,[...]
although static members can be incomplete, section 9.4.2 Static data members paragraph 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.[...]
It also makes sense to not allow a class to contain itself since this would require infinite space since the self reference would never end, A contains A which contains A ...
Related
class Solution {
public:
static int m=INT_MIN; // it shows error: non-const static data member must
be initialized out of line.(why?)
using "int m=INT_MIN" is fine.
int func(TreeNode*root){
if(root==NULL){
return 0;
}
int l=max(func(root->left),0);
int r=max(func(root->right),0);
m=max(l+r+root->val,m);
return max(l,r)+root->val;
}
int maxPathSum(TreeNode* root) {
if(root==NULL)
{
return 0;
}
m=INT_MIN;
int x=func(root);
return m;
}
};
I need to update the value of variable m. Therefore I am using static int data type. But the following error is coming.
Using int instead of static int is working fine. But why is static int giving error?
Bjarne Stroustrup explains this 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.
As said by Stroustrup, every class needs a unique definition. Now, as we know static members are associated directly with their class. Now consider the two cases:
The static member is also constant, then its initialization is allowed inline because the compiler can make its own optimisations and treat this member as a compile-time constant because it is guaranteed that its value will never change. So, as the value of this member is fixed, the definition of the class with which this member is associated is also fixed. So, the initialization is allowed inline.
The static member is not constant. Then its value can change later on during the execution of the program. So, the compiler can not make compile-time optimisations on this member. Hence, to prevent the complications that may arise while trying to initialize such a member when the class is loaded, inline initialisation of such members is not allowed.
PS: When I heard about this concept the very first time, I was also confused because it is not in accordance with the principle of orthogonality that is a feature desired by programmers. The principle of orthogonality will state that since we can combine int and static; and int and const, we should be able to write static const int and static int in a similar fashion. But this case here is an example of a situation where the developer of a language has to give up orthogonality for the users of the language in exchange of the simplicity of the compilation process.
Have a look at the concept of orthogonality here
To answer OPs question why
class Solution {
public:
int m = INT_MIN;
};
is fine but
class Solution {
public:
static int m = INT_MIN;
};
is not:
In short: Prefixing a data-member with static fundamentally change its meaning.
Without static, the member variable is part of the class and each instance will provide a separate storage for this member variable.
With static, the member variable has only scope of the class but there will be only one global storage.
Respectively, the initialization has different meanings too.
For non-static member variables, it provides a default initialization which constructors may use (or override).
Demonstration by Example:
#include <iostream>
enum ArgCase1 { Case1 };
enum ArgCase2 { Case2 };
class Solution {
public:
int m = 123;
Solution() = default; // will use m(123) implicitly
Solution(ArgCase1) { } // will use m(123) implicitly
Solution(ArgCase2): m(456) { } // default of m ignored
};
#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__
int main()
{
DEBUG(Solution sol);
std::cout << "sol.m: " << sol.m << '\n';
DEBUG(Solution sol1(Case1));
std::cout << "sol1.m: " << sol1.m << '\n';
DEBUG(Solution sol2(Case2));
std::cout << "sol2.m: " << sol2.m << '\n';
}
Output:
Solution sol;
sol.m: 123
Solution sol1(Case1);
sol1.m: 123
Solution sol2(Case2);
sol2.m: 456
Live Demo on coliru
For static member variables, the initialization would be dangerous. Assuming that a class is declared in a header which is included multiple times, this would result in a violation of the One Definition Rule.
In former times, it was usual to declare the static member variable in the header but to define it in the .cpp-file (which represents the translation unit).
Expample:
solution.h:
#ifndef SOLUTION_H
#define SOLUTION_H
class Solution {
public:
static int m;
};
#endif // SOLUTION_H
solution.cc:
// header of this module:
#include "solution.h"
int Solution::m = 123;
Live Demo on coliru
Since C++17, a new alternative is available – using the keyword inline.
From cppreference.com – static members – Static data members
A static data member may be declared inline. An inline static data member can be defined in the class definition and may specify an initializer. It does not need an out-of-class definition
Example:
solution.h:
#ifndef SOLUTION_H
#define SOLUTION_H
class Solution {
public:
inline static int m = 123;
};
#endif // SOLUTION_H
Live Demo on coliru
The advantage is that there is no .cpp-file needed for this i.e. as it is the class Solution could be provided as header-only source.
In C++11, I am trying to access a member variable of an enclosing class from a nested class in the following way:
struct Enclosing {
int a;
struct Nested {
int f() {
return a;
}
};
};
Even this doesn't compile using g++4.7.2 with -std=c++11, producing error messages of this form:
error: invalid use of non-static data member 'Enclosing::a'
As far as I understand, C++11 treats a nested class as a member of the class, so that supposedly a nested class can access every other member of the enclosing class. Did I do something wrong? Thanks in advance.
Update:
While my question seems to have an answer below, I am not convinced this shall be flagged as duplicate.
I am aware of discussions on the relationship between nested classes and enclosing classes before the C++11 standard, after a lot of searching before posting a question.
Previous relevant discussions like this cite some "updates" in C++11, e.g. C++ nested classes accessibility
But it was not very clear, at least from answers I've read, the full extent that C++11 is "different" from older versions on this matter.
Technically the solution to my question exists in older threads such as
Nested class' access to enclosing class' private data members, a fact that had to be pointed out, however inane it makes me seem. But I did not come by any such answer that puts C++11 into context; at least, I don't think my question can be fairly deemed a "duplicate" of a question asked before the C++11 standard.
Here is the change within C++11 from cppreference;
Declarations in a nested class can use only type names, static
members, and enumerators from the enclosing class (until C++11)
Declarations in a nested class can use any members of the enclosing
class, following the usual usage rules for the non-static members.
(since C++11)
int x,y; // globals
class enclose { // enclosing class
int x; // note: private members
static int s;
public:
struct inner { // nested class
void f(int i) {
x = i; // Error: can't write to non-static enclose::x without instance
int a = sizeof x; // Error until C++11,
// OK in C++11: operand of sizeof is unevaluated,
// this use of the non-static enclose::x is allowed.
s = i; // OK: can assign to the static enclose::s
::x = i; // OK: can assign to global x
y = i; // OK: can assign to global y
}
void g(enclose* p, int i) {
p->x = i; // OK: assign to enclose::x
}
};
};
In brief, within C++11, nested class can refer to types and static members of its enclosing class. In addition, it can refer to non-static members only when object of the enclosing class is given to the nested class. A nested class has access to members of its enclosing class including private members.
To close this question I'll take this as an answer:
"No, it's not treated as a member of the class, it's just scoped inside of it like anything else. You'll need an instance of Enclosing to access it's members."
this and several other comments addresses the problem in my code. Basically this is something that remains true for C++11.
I wonder if there is a reason why we can't initialize members at their declaration.
class Foo
{
int Bar = 42; // this is invalid
};
As an equivalent of using constructor initialization lists.
class Foo
{
int Bar;
public:
Foo() : Bar(42) {}
}
My personal understanding is that the above example is much more expressive and intentional. Moreover this is a shorter syntax. And I don't see any possibility of confusion with other language elements.
Is there any official clarification about this?
The initialization of non-static members could not be done like this prior to C++11. If you compile with a C++11 compiler, it should happily accept the code you have given.
I imagine that the reason for not allowing it in the first place is because a data member declaration is not a definition. There is no object being introduced. If you have a data member such as int x;, no int object is created until you actually create an object of the type of the class. Therefore, an initializer on this member would be misleading. It is only during construction that a value can be assigned to the member, which is precisely what member initialization lists are for.
There were also some technical issues to iron out before non-static member initialization could be added. Consider the following examples:
struct S {
int i(x);
// ...
static int x;
};
struct T {
int i(x);
// ...
typedef int x;
};
When these structs are being parsed, at the time of parsing the member i, it is ambiguous whether it is a data member declaration (as in S) or a member function declaration (as in T).
With the added functionality, this is not a problem because you cannot initialize a member with this parantheses syntax. You must use a brace-or-equal-initializer such as:
int i = x;
int i{x};
These can only be data members and so we have no problem any more.
See the proposal N2628 for a more thorough look at the issues that had to be considered when proposing non-static member initializers.
The main reason is that initialization applies to an object, or
an instance, and in the declaration in the class there is no
object or instance; you don't have that until you start
constructing.
There's been some evolution in this regard. Already, at the
very end of standardization of C++98, the committee added the
possibility to do this for static const members of integral
type---mainly because these can be used in contexts where the
compiler must be able to see the initialization. In C++11, the
language has been extended to allow specifying an initializer in
the declaration, but this is just a shorthand—the actual
initialization still takes place at the top of the constructor.
When two or more objects(instance of the class) are declared, those objects share these data members. so value can be initialized with the help of constructor. so we can't initialize the class members during declaration.
Before C++11, we could only perform in-class initialization on static const members of integral or enumeration type. Stroustrup discusses this in his C++ FAQ, giving the following example:
class Y {
const int c3 = 7; // error: not static
static int c4 = 7; // error: not const
static const float c5 = 7; // error: not integral
};
And the following reasoning:
So why do these inconvenient restrictions exist? 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.
However, C++11 relaxes these restrictions, allowing in-class initialization of non-static members (§12.6.2/8):
In a non-delegating constructor, if a given non-static data member or base class is not designated by a mem-initializer-id (including the case where there is no mem-initializer-list because the constructor has no ctor-initializer) and the entity is not a virtual base class of an abstract class (10.4), then
if the entity is a non-static data member that has a brace-or-equal-initializer, the entity is initialized as specified in 8.5;
otherwise, if the entity is a variant member (9.5), no initialization is performed;
otherwise, the entity is default-initialized (8.5).
Section 9.4.2 also allows in-class initialization of non-const static members if they are marked with the constexpr specifier.
So what happened to the reasons for the restrictions we had in C++03? Do we just simply accept the "complicated linker rules" or has something else changed that makes this easier to implement?
The short answer is that they kept the linker about the same, at the expense of making the compiler still more complicated than previously.
I.e., instead of this resulting in multiple definitions for the linker to sort out, it still only results in one definition, and the compiler has to sort it out.
It also leads to somewhat more complex rules for the programmer to keep sorted out as well, but it's mostly simple enough that it's not a big deal. The extra rules come in when you have two different initializers specified for a single member:
class X {
int a = 1234;
public:
X() = default;
X(int z) : a(z) {}
};
Now, the extra rules at this point deal with what value is used to initialize a when you use the non-default constructor. The answer to that is fairly simple: if you use a constructor that doesn't specify any other value, then the 1234 would be used to initialize a -- but if you use a constructor that specifies some other value, then the 1234 is basically ignored.
For example:
#include <iostream>
class X {
int a = 1234;
public:
X() = default;
X(int z) : a(z) {}
friend std::ostream &operator<<(std::ostream &os, X const &x) {
return os << x.a;
}
};
int main() {
X x;
X y{5678};
std::cout << x << "\n" << y;
return 0;
}
Result:
1234
5678
I guess that reasoning might have been written before templates were finalized. After all the "complicated linker rule(s)" necessary for in-class initializers of static members was/were already necessary for C++11 to support static members of templates.
Consider
struct A { static int s = ::ComputeSomething(); }; // NOTE: This isn't even allowed,
// thanks #Kapil for pointing that out
// vs.
template <class T>
struct B { static int s; }
template <class T>
int B<T>::s = ::ComputeSomething();
// or
template <class T>
void Foo()
{
static int s = ::ComputeSomething();
s++;
std::cout << s << "\n";
}
The problem for the compiler is the same in all three cases: in which translation-unit should it emit the definition of s and the code necessary to initialize it? The simple solution is to emit it everywhere and let the linker sort it out. That's why the linkers already supported things like __declspec(selectany). It just wouldn't have been possible to implement C++03 without it. And that's why it wasn't necessary to extend the linker.
To put it more bluntly: I think the reasoning given in the old standard is just plain wrong.
UPDATE
As Kapil pointed out, my first example isn't even allowed in the current standard (C++14). I left it in anyway, because it IMO is the hardest case for the implementation (compiler, linker). My point is: even that case is not any harder than what's already allowed e.g. when using templates.
In theory So why do these inconvenient restrictions exist?... reason is valid but it can rather be easily bypassed and this is exactly what C++ 11 does.
When you include a file, it simply includes the file and disregards any initialization. The members are initialized only when you instantiate the class.
In other words, the initialization is still tied with constructor, just the notation is different and is more convenient. If the constructor is not called, the values are not initialized.
If the constructor is called, the values are initialized with in-class initialization if present or the constructor can override that with own initialization. The path of initialization is essentially the same, that is, via the constructor.
This is evident from Stroustrup own FAQ on C++ 11.
As we know,It is possible to initialize integral const static members inside the class structure.This is useful when the constant is used in the class structure after the initialization.For example,it can be used as the size of an int array.
Look the code following:
class MyClass{
static const int num = 100;
int elems[num];
...
};
But we still have to define the member num outside the class definition:
const int MyClass::num;
I don't know why we have to do like this.
Could someone tell me why?
Thanks a lot.
In addition,I write the following code:
#include <iostream>
using namespace std;
class MyClass{
public:
MyClass()
{
cout << "instruct class MyClass!" << endl;
}
static const int num = 100;
int elems[num];
};
//const int MyClass::num;
int main()
{
MyClass a;
const int *b = &(a.num);
cout << "&(a.num): " << &(a.num) << endl;
cout << "a.num: " << a.num << endl;
cout << "*b: " << *b << endl;
}
It runs well on Visual Studio 2008:
But I have removed the code that definite the member num outside the class.
I am very confused.Could someone interpret it for me?
The initialization in the class is mainly used to obtain a constant expression. For this only the value matters. Once you take the address of the object or bind it to a reference, the compiler needs a location for the object as well. This is effectively what the definition provides.
You would need to define the static constant num outside the class in a cpp file only if your code takes it's address.This is known as an Out-of-class definition.
If your code does not take address of num, then the In-class Initialization would just work fine.
Rationale:
Bjarne states:
"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 the above rule mentioned by Bjarne.
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 because then the compiler needs to place them in memory.