class data
{
private:
int ID;
string address,name;
public:
data(int i,string a,string n):ID(i),address(a),name(n){}
friend class SetData;
};
class SetData
{
private:
data obj(43,"185 Awan Market","Talha"); //this is where the error happens
public:
void show()
{
cout<<"Name is: "<<obj.name<<endl;
cout<<"Address is: "<<obj.address<<endl;
cout<<"ID is: "<<obj.ID;
}
};
C++03
It belongs in the constructor's mem-initializer:
class SetData
{
private:
data obj;
public:
SetData() : obj(43,"185 Awan Market","Talha")
{
}
// Rest goes here...
};
C++11
You must use a brace or equal initializer.
// Fine
data obj{43,"185 Awan Market","Talha"};
// Fine, too
data obj = data(43,"185 Awan Market","Talha"); //this is where the error happens
For why parentheses are not allowed, see the Non-static data member initializers proposal. Scroll down to "An issue raised in Kona regarding scope of identifiers"
The motivation for class-scope lookup is that we’d like to be able to
put anything in a non-static data member’s initializer that we could
put in a mem-initializer without significantly changing the semantics
(modulo direct initialization vs. copy initialization):
int x();
struct S {
int i;
S() : i(x()) {} // currently well-formed, uses S::x()
// ...
static int x();
};
struct T {
int i = x(); // should use T::x(), ::x() would be a surprise
// ...
static int x();
};
Unfortunately, this makes initializers of the “( expression-list )”
form ambiguous at the time that the declaration is being parsed:
struct S {
int i(x); // data member with initializer
// ...
static int x;
};
struct T {
int i(x); // member function declaration
// ...
typedef int x;
};
One possible solution is to rely on the existing rule that, if a
declaration could be an object or a function, then it’s a function:
struct S {
int i(j); // ill-formed...parsed as a member function,
// type j looked up but not found
// ...
static int j;
};
A similar solution would be to apply another existing rule, currently
used only in templates, that if T could be a type or something else,
then it’s something else; and we can use “typename” if we really mean
a type: Essentially
struct S {
int i(x); // unabmiguously a data member
int j(typename y); // unabmiguously a member function
};
Both of those solutions introduce subtleties that are likely to be
misunderstood by many users (as evidenced by the many questions on
comp.lang.c++ about why “int i();” at block scope doesn’t declare a
default-initialized int).
The solution proposed in this paper is to allow only initializers of
the “= initializer-clause” and “{ initializer-list }” forms. That
solves the ambiguity problem in most cases, for example:
HashingFunction hash_algorithm{"MD5"};
Initializing non-static data members in such a way is not allowed. You should rather be using a brace-or-equal initializer
class SetData
{
private:
// data obj = {43,"185 Awan Market","Talha"}; is also valid
data obj{43,"185 Awan Market","Talha"};
Cfr. non-static data members initialization
Alternative solution: constructor initializer list
class SetData
{
private:
data obj;
public:
SetData() : obj(43,"185 Awan Market","Talha") {}
void show()
...
};
As to why parenthesis are not supported for non-static data members initialization, I recommend reading this post: Why C++11 in-class initializer cannot use parentheses?
You can't initialize objects inline like that, you have to do it in the constructors initializer list:
class SetData
{
private:
data obj;
public:
SetData() : obj(43,"185 Awan Market","Talha") {}
...
};
Related
Someone gave me (part of) the following code:
struct MyStruct
{
int x = {};
int y = {};
};
I never saw this syntax before, what does initialization with {} mean?
This is default member initializer (since C++11),
Through a default member initializer, which is a brace or equals initializer included in the member declaration and is used if the member is omitted from the member initializer list of a constructor.
The initialization itself is copy-list-initialization (since C++11), as the effect, the data member x and y would be value-initialized (and zero-initialized as built-in type) to 0.
Since the C++11 standard there are two ways to initialize member variables:
Using the constructor initialization list as "usual":
struct Foo
{
int x;
Foo()
: x(0)
{
}
};
Use the new inline initialization where members are getting their "default" values using normal initialization syntax:
struct Foo
{
int x = 0;
};
Both these ways are for many values and types equivalent.
I have a in-class initialized const member in a derived class which I'd like to pass to the constructor of the base class.
Example:
class Base{
public:
Base(int a) : i(a){}
private:
int i;
};
class Derived : Base{
public:
Derived() : Base(a){}
private:
const int a = 7;
};
int main(){
Derived d;
}
However this spawns an uninitialized error:
field 'a' is uninitialized when used here [-Wuninitialized]
I was under the impression that const initializing it would set the value directly allowing it to be passed from the derived ctor in this manner. Am I doing something wrong or am I under the wrong impression? When are the const in-class initialized members initialized?
When initializing base classes and class members during creation of an object, the order of initialization is:
Virtual base classes, in tree order
Direct non-virtual base classes, in order
Non-static data members, in their order of declaration.
So Base(a) happens before a = 7 happens.
One way to fix this would be to make a be static const or static constexpr. This is probably a good idea anyway, because non-static const variables make your class more difficult to use. (e.g. there will not be an implicitly-generated copy-constructor).
Your question,
When are the const in-class initialized members initialized?
is a bit of a red herring. "in-class initialized" doesn't really mean anything; the brace-or-equal initializer is essentially just syntactic sugar and takes the place of the corresponding constructor initalizer list slot. const also has no special bearing. So the real question should be:
When are non-static data members initialized?
The details don't actually matter so much, suffice to say that non-static data members are initialized after base subobjects are initialized, so your proposed construction cannot work.
The straight-forward answer is not to use a brace-or-equals-initializer and just use a normal (possibly defaulted) constructor parameter. Here are a few examples:
struct Foo : Base
{
const int a;
// Default constructor, mention value only once
Foo(int _a = 10) : Base(_a), a(_a) {}
// DRYolent default constructor
Foo() : Base(10), a(10) {}
// Delegating default constructor
Foo() : Foo(10) {}
private: Foo(int _a) : Base(_a), a(_a) {}
};
Alternatively, if the value of the constant doesn't need to be configurable, then you can make it a per-class constant (rather than per-object):
struct Foo : Base
{
static const int a = 10;
Foo() : Base(a) {}
};
const int Foo::a; // only if you ODR-use Foo::a
I run across a weird concept named "member initializer".
Here says:
C++11 added member initializers, expressions to be applied to members
at class scope if a constructor did not initialize the member itself.
What is its definition?
Are there some examples to illustrate its usage?
It probably refers to in-class member initializers. This allows you to initialize non-static data members at the point of declaration:
struct Foo
{
explicit Foo(int i) : i(i) {} // x is initialized to 3.1416
int i = 42;
double x = 3.1416;
};
More on that in Bjarne Stroustrup's C++11 FAQ.
You can now add initializers in the class which are shared for the constructors:
class A
{
int i = 42;
int j = 1764;
public:
A() {} // i will be 42, j will be 1764
A( int i ) : i(i) {} // j will be 1764
};
It avoids having to repeat initializers in the constructor which, for large classes, can be a real win.
C++11 allows non-static member initialization like this:
class C
{
int a = 2; /* This was not possible in pre-C++11 */
int b;
public:
C(): b(5){}
};
Member initializers is referring to the extension of what initializers can be set up in the class definition. For example, you can use
struct foo
{
std::string bar = "hello";
std::string baz{"world"};
foo() {} // sets bar to "hello" and baz to "world"
foo(std::string const& b): bar(b) {} // sets bar to b and baz to "world"
};
to have bar initialized to hello if the member initializer list doesn't give another value. Note that member initializers are not restricted to build-in types. You can also use uniform initialization syntax in the member initializer list.
From here:-
Non-static Data Member Initializers are a rather straightforward new
feature. In fact the GCC Bugzilla reveals novice C++ users often tried
to use it in C++98, when the syntax was illegal! It must be said that
the same feature is also available in Java, so adding it to C++ makes
life easier for people using both languages.
struct A
{
int m;
A() : m(7) { }
};
struct B
{
int m = 7; // non-static data member initializer
};
thus the code:
A a;
B b;
std::cout << a.m << '\n';
std::cout << b.m << std::endl;
OK, member variables can be used to initialize other member variables in an initialization list (with care taken about the initialization order etc). What about member functions? To be specific, is this snippet legal according to the C++ standard?
struct foo{
foo(const size_t N) : N_(N), arr_(fill_arr(N)) {
//arr_ = fill_arr(N); // or should I fall back to this one?
}
std::vector<double> fill_arr(const size_t N){
std::vector<double> arr(N);
// fill in the vector somehow
return arr;
}
size_t N_;
std::vector<double> arr_;
// other stuff
};
Yes, your use of member function in initialization list is valid and complies with the standard.
Data members are initialized in the order of their declaration (and that's the reason why they should appear in the initialization list in the order of their declaration - the rule that you followed in your example). N_ is initialized first and you could have passed this data member to fill_arr. fill_arr is called before constructor but because this function does not access uninitialized data members (it does not access data members at all) its call is considered safe.
Here are some relevant excepts from the latest draft (N3242=11-0012) of the C++ standard:
§ 12.6.2.13: Member functions (including virtual member functions,
10.3) can be called for an object under construction.(...) However, if these operations are performed in a ctor-initializer (or in a function
called directly or indirectly from a ctor-initializer) before all the
mem-initializers for base classes have completed, the result of the
operation is undefined. Example:
class A { public: A(int); };
class B : public A {
int j;
public:
int f();
B() : A(f()), // undefined: calls member function
// but base A not yet initialized
j(f()) { } // well-defined: bases are all initialized
};
class C {
public:
C(int);
};
class D : public B, C {
int i;
public:
D() : C(f()), // undefined: calls member function
// but base C not yet initialized
i(f()) { } // well-defined: bases are all initialized
};
§12.7.1: For an object with a non-trivial constructor, referring to
any non-static member or base class of the object before the
constructor begins execution results in undefined behavior. Example
struct W { int j; };
struct X : public virtual W { };
struct Y {
int *p;
X x;
Y() : p(&x.j) { // undefined, x is not yet constructed
}
};
While initializing objects in the initialization list, the object is not yet fully constructed.
If those function tries to access the part of the object which is not yet constructed then that is a undefined behavior else its fine.
see this answer.
Internally and about the generated code, is there a really difference between :
MyClass::MyClass(): _capacity(15), _data(NULL), _len(0)
{
}
and
MyClass::MyClass()
{
_capacity=15;
_data=NULL;
_len=0
}
thanks...
You need to use initialization list to initialize constant members,references and base class
When you need to initialize constant member, references and pass parameters to base class constructors, as mentioned in comments, you need to use initialization list.
struct aa
{
int i;
const int ci; // constant member
aa() : i(0) {} // will fail, constant member not initialized
};
struct aa
{
int i;
const int ci;
aa() : i(0) { ci = 3;} // will fail, ci is constant
};
struct aa
{
int i;
const int ci;
aa() : i(0), ci(3) {} // works
};
Example (non exhaustive) class/struct contains reference:
struct bb {};
struct aa
{
bb& rb;
aa(bb& b ) : rb(b) {}
};
// usage:
bb b;
aa a(b);
And example of initializing base class that requires a parameter (e.g. no default constructor):
struct bb {};
struct dd
{
char c;
dd(char x) : c(x) {}
};
struct aa : dd
{
bb& rb;
aa(bb& b ) : dd('a'), rb(b) {}
};
Assuming that those values are primitive types, then no, there's no difference. Initialization lists only make a difference when you have objects as members, since instead of using default initialization followed by assignment, the initialization list lets you initialize the object to its final value. This can actually be noticeably faster.
Yes. In the first case you can declare _capacity, _data and _len as constants:
class MyClass
{
private:
const int _capacity;
const void *_data;
const int _len;
// ...
};
This would be important if you want to ensure const-ness of these instance variables while computing their values at runtime, for example:
MyClass::MyClass() :
_capacity(someMethod()),
_data(someOtherMethod()),
_len(yetAnotherMethod())
{
}
const instances must be initialized in the initializer list or the underlying types must provide public parameterless constructors (which primitive types do).
I think this link http://www.cplusplus.com/forum/articles/17820/ gives an excellent explanation - especially for those new to C++.
The reason why intialiser lists are more efficient is that within the constructor body, only assignments take place, not initialisation. So if you are dealing with a non-built-in type, the default constructor for that object has already been called before the body of the constructor has been entered. Inside the constructor body, you are assigning a value to that object.
In effect, this is a call to the default constructor followed by a call to the copy-assignment operator. The initialiser list allows you to call the copy constructor directly, and this can sometimes be significantly faster (recall that the initialiser list is before the body of the constructor)
I'll add that if you have members of class type with no default constructor available, initialization is the only way to construct your class.
A big difference is that the assignment can initialize members of a parent class; the initializer only works on members declared at the current class scope.
Depends on the types involved. The difference is similar between
std::string a;
a = "hai";
and
std::string a("hai");
where the second form is initialization list- that is, it makes a difference if the type requires constructor arguments or is more efficient with constructor arguments.
The real difference boils down to how the gcc compiler generate machine code and lay down the memory. Explain:
(phase1) Before the init body (including the init list): the compiler allocate required memory for the class. The class is alive already!
(phase2) In the init body: since the memory is allocated, every assignment now indicates an operation on the already exiting/'initialized' variable.
There are certainly other ways to handle const type members. But to ease their life, the gcc compiler writers decide to set up some rules
const type members must be initialized before the init body.
After phase1, any write operation only valid for non-constant members.
There is only one way to initialize base class instances and non-static member variables and that is using the initializer list.
If you don't specify a base or non-static member variable in your constructor's initializer list then that member or base will either be default-initialized (if the member/base is a non-POD class type or array of non-POD class types) or left uninitialized otherwise.
Once the constructor body is entered, all bases or members will have been initialized or left uninitialized (i.e. they will have an indeterminate value). There is no opportunity in the constructor body to influence how they should be initialized.
You may be able to assign new values to members in the constructor body but it is not possible to assign to const members or members of class type which have been made non-assignable and it is not possible to rebind references.
For built in types and some user-defined types, assigning in the constructor body may have exactly the same effect as initializing with the same value in the initializer list.
If you fail to name a member or base in an initializer list and that entity is a reference, has class type with no accessible user-declared default constructor, is const qualified and has POD type or is a POD class type or array of POD class type containing a const qualified member (directly or indirectly) then the program is ill-formed.
If you write an initializer list, you do all in one step; if you don't write an initilizer list, you'll do 2 steps: one for declaration and one for asign the value.
There is a difference between initialization list and initialization statement in a constructor.
Let's consider below code:
#include <initializer_list>
#include <iostream>
#include <algorithm>
#include <numeric>
class MyBase {
public:
MyBase() {
std::cout << __FUNCTION__ << std::endl;
}
};
class MyClass : public MyBase {
public:
MyClass::MyClass() : _capacity( 15 ), _data( NULL ), _len( 0 ) {
std::cout << __FUNCTION__ << std::endl;
}
private:
int _capacity;
int* _data;
int _len;
};
class MyClass2 : public MyBase {
public:
MyClass2::MyClass2() {
std::cout << __FUNCTION__ << std::endl;
_capacity = 15;
_data = NULL;
_len = 0;
}
private:
int _capacity;
int* _data;
int _len;
};
int main() {
MyClass c;
MyClass2 d;
return 0;
}
When MyClass is used, all the members will be initialized before the first statement in a constructor executed.
But, when MyClass2 is used, all the members are not initialized when the first statement in a constructor executed.
In later case, there may be regression problem when someone added some code in a constructor before a certain member is initialized.
Here is a point that I did not see others refer to it:
class temp{
public:
temp(int var);
};
The temp class does not have a default ctor. When we use it in another class as follow:
class mainClass{
public:
mainClass(){}
private:
int a;
temp obj;
};
the code will not compile, cause the compiler does not know how to initialize obj, cause it has just an explicit ctor which receives an int value, so we have to change the ctor as follow:
mainClass(int sth):obj(sth){}
So, it is not just about const and references!