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.
Related
Why and when does the compiler optimize away static member variables? I have the following code
#include <iostream>
#include <typeinfo>
class X {
public:
X(const char* s) { std::cout << s << "\n"; };
};
template <class S> class Super {
protected:
Super() { (void)m; };
static inline X m { typeid(S).name() };
};
class A : Super<A> {
};
class B : Super<B> {
B() {};
};
class C {
static inline X m { "c" };
};
A a {};
int main() { return 0; }
On the output I can see that Super<A>::m, Super<B>:m, and C::m are all initialized.
Super<A>::m is not initialized if the statement A a {}; is removed. It makes sense because then m is never accessed. However this does not explain why it is not removed for B and C.
Is this behavior specified or is it an artifact of how the compiler detects unused variables?
The definition of a static data member of a class template specialization is implicitly instantiated only if it is used in such a way that a definition would be required.
For the class B you are, unconditionally, defining the default constructor. The default constructor uses the default constructor of Super<B> to initialize the base, meaning that the definition of the Super<B>::Super() constructor will be implicitly instantiated. This constructor's definition is odr-using m in (void)m; and therefore Super<B>::m's definition will also be implicitly instantiated.
In the case of class A, you are not explicitly defining any constructor. The implicit special member functions will be defined only when they are used in such a way that a definition would be required. In the line A a {}; you are calling the implicit default constructor of A and hence it will be defined. The definition will be calling the default constructor of Super<A> as before, requiring the Super<A>::m's definition to be instantiated. Without A a {}; there is nothing in the code requiring a definition of any special member function of A or the default constructor of Super<A> or the definition of m. Therefore none of them will be defined.
In the case of C, there is no template for which we would need to consider instantiation. C::m is explicitly defined.
Given that the static data member is defined, it must (generally) be initialized eventually. All of the inline static data members here have dynamic initialization with observable side effects, so the initialization must happen at runtime. It is implementation-defined whether they will be initialized before main's body starts execution or whether initialization will be deferred upto the first non-initialization odr-use of the inline static data member. (This is meant to allow for dynamic libraries.)
You aren't actually non-initialization odr-using any of the inline static data members, so it is implementation-defined whether they will actually be initialized at all. If the implementation does define the initialization to not be deferred, then all of these inline static data members which have been defined will also be initialized before main is entered.
The order in which the initializations will happen is indeterminate. The static data members of the class template specializations have unordered initialization, meaning they have no ordering guarantees with any other dynamic initialization. And there is only one static data member which isn't specialized from a template and that one is inline and therefore only partially ordered, although there is nothing else it could be ordered with.
Actually, there is one additional static storage duration object which will be initialized here, a global variable of type std::ios_base::Init included through <iostream>. The initialization of this variable causes the initialization of the standard streams (std::cout, etc.). Because your inline static data members from the templates have unordered initialization, they will not be ordered with this initialization. Similarly if you had multiple translation units containing C::m, it would also not be ordered with it. As a consequence you might be using std::cout before it is initialized, causing undefined behavior. You can cause early initialization of the standard streams by constructing an object of type std::ios_base::Init:
class X {
public:
X(const char* s) {
[[maybe_unused]] std::ios_base::Init ios_base_init;
std::cout << s << "\n";
};
};
Aside from considerations such as above, the compiler is not allowed to remove static data members if their initialization has observable side effects. Of course the as-if rule still applies as always meaning that the compiler can compile to whatever machine instructions which will result in the same observable behavior as described above.
For practical purposes you should also be careful. There are some compiler flags that are sometimes used for code size optimization which will eliminate dynamic initialization if the variable seems to be unused. (Although that is not standard-conforming behavior.) For example the --gc-sections linker flag together with GCC's -ffunction-section -fdata-section can have this effect.
As you can see dynamic initialization of static storage duration objects is kind of complicated in C++. In your case here there are only minor dependency issues, but this can quickly become very messy, which is why it is usually recommended to avoid it as much as possible.
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 always thought that if I declare member of a class inside class this member is known at the entire scope of a class that is:
class X
{
public:
X(int a) :v_(a)
{}
private:
int v_;//even though v_ is declared here I'm using it in ctor which is above this line
};
So that makes sense to me.
Anyhow this doesn't because I'm getting error that v_ isn't known
class X
{
public:
X(decltype(v_) a) :v_(a)//error on this line, compiler doesn't know v_
{}
private:
int v_;
};
Would be glad to learn why.
I'm using intel compiler v14 SP1
Thank you.
3.3.7 Class scope
1 The following rules describe the scope of names declared in classes.
1) The potential scope of a name declared in a class consists not only of the declarative region following
the name’s point of declaration, but also of all function bodies, brace-or-equal-initializers of non-static
data members, and default arguments in that class (including such things in nested classes).
...
That means that you can use v_ in function bodies, constructor initializer lists and default arguments. You are not allowed to use v_ in parameter declarations the way you used it in your code.
For example, this shall compile
class X
{
public:
X(int a = decltype(v_)()) : v_(a)
{}
private:
int v_;
};
but not the second example in your original post.
Your code compiles with Clang.
Reading C++11 specifications you are not allowed to declare the variable after it is being used as function/constructor parameter.
In many cases classes including function signatures will be defined in headers, but function bodies in cpp files. Since the header will have been read by the compiler at the start of reading the cpp file, this problem does usually not occur. But indeed, C++ compilers don't look ahead.
Consider the following code:
struct test {
auto func() -> decltype(data) {} // ERROR
int data;
};
int main() {
test t;
t.func();
}
It gives the following error:
main.cpp:2:29: error: 'data' was not declared in this scope
auto func() -> decltype(data) {}
However, if I place data above func(), it gives out no error (live code):
struct test {
int data;
auto func() -> decltype(data) {}
};
...
And so my question is, why is decltype not considering members declared after it (when decltype is used in a method declaration, not in the definition)? I also want to know if there are any change in this behavior in future iterations of the language standard.
Please note that I'm asking this because I was expecting decltype to behave differently. My coding convention is to place class data members below the class functions. Surely this different behavior would affect how I organize my class members. I would be very grateful if you can provide any workaround that would preserve my coding convention.
The trailing return type is part of the member function declaration, which does not have access to data members or member functions declared after it, unlike the member function definition, which does. I am not aware of any change in this behaviour in C++14.
See 3.4.1-7 of the C++11 standard, Unqualified name look-up:
A name used in the definition of a class X outside of a member function body or nested class definition
shall be declared in one of the following ways:
before its use in class X or be a member of a base class of X (10.2), or...
(emphasis mine)
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.