Is modify const in constructor C++ standard? I was modifying my struct removing fixed-values(default member initializer) to set it later, at constructor-time but I forget to remove const keyword and noticied it later. To my surprise I didn't get a compile-error, it just worked fine but for test case 2 it give a compiler. How are they different?
test case 1:
struct A
{
const int x = 2;
A()
: x(3)
{
}
};
test case 2:
struct A
{
const int x = 2;
A()
{
x = 3; // compile error! error: read-only variable is not assignable
}
};
In the first example you are initializing the constant variable, in the second you are assigning a value to it, after the variable is default constructed. These are different operations and assignment is not possible for constants after their initialization.
This syntax was added in C++11:
struct A
{
const int x = 2;
In this case the 2 is like a "default" value to be used for initialization of x. If you initialize x in your constructor's initialization list, then that is the value used. However if you did not do so, then 2 is used.
This was added to C++11 to avoid the tedium of having to repeat things in the initialization lists if you had multiple constructors.
The thing is that the object must be fully initialized before the body of your constructor can proceed to start playing with it. This means that there must be reserved enough space in memory to which the instance of new object will be placed.
If you declare data member (int x) to be const, you prohibit yourself from ever changing it's value, once it is created, this means that the value must be set during it's creation.
In example 1 you first create the int x and set it to value 3 (which will reside in memory reserved for your object) and only after that the body of your constructor executes.
In example 2 you create new object (with some value for your int x) and than you try to modify it in your constructor, which is prohibited by the const keyword.
Related
I am new to c++ and I want to learn best practice of c++. I got one question, does the modern c++ compiler will auto assign default value for an uninitialized variable? If yes, does it mean that we do not need to assign default value to a variable or it depends on system?
Thank you for your help and clarification.
Only static and global data is always initialised...
int w; // will be 0
static int x; // will be 0
void f() { static int x; /* will be 0 the first time this scope's entered */ }
struct S
{
int n_;
};
S s_; // s_.n_ will be 0 as s_ is global
int main()
{
S s; // s.n_ will be uninitialised
// undefined behaviour to read before setting
}
For any other variables they must have - at some level in the code - explicit initialisation before they're read from. That might not be visible at the point a variable is declared though - it could be in a default constructor or an assignment. You can also cause initialisation like this:
int x{}; // will be 0
int* p = new int{}; // *p will be 0
Default initialization is performed in three situations:
1) when a variable with automatic, static, or thread-local storage duration is declared with no initializer.
2) when an object with dynamic storage duration is created by a new-expression with no initializer or when an object is created by a new-expression with the initializer consisting of an empty pair of parentheses (until C++03).
3) when a base class or a non-static data member is not mentioned in a constructor initializer list and that constructor is called.
More information here:
http://en.cppreference.com/w/cpp/language/default_initialization
With regard to what the compiler will do I think its more of the inverse, for example:
int x; // still must be inited, will contain random data
if (some_func())
{
// some devs will do this for "performance" - i.e don't assign a value to x
x = 2;
}
But if you write:
int x = 0;
if (some_func())
{
x = 2;
}
The compiler will optimize this to:
int x;
if (some_func())
{
x = 2; // Yes this code is actually the first example again :)
}
Assuming x is not used else where in the function.
probably this might be a very basic question, but still wanna understand some basic concepts...
why do we define a variable as a const ? - to keep the value of that specific variable constant through out the program.
but, when i come across initialization list for constructors, that allows to assign value to the const variable during object construction( i tried the below program for ex.), i'm confused with the basic concept of const keyword itself. can someone clarify this?
what is the purpose of const variable in the following program, if it is allowed to change during object construction? do we have any real time scenarios for these kinda behavior? if so, can you please give some scenarios?
#include<iostream>
using namespace std;
class Test {
const int t;
public:
Test(int t):t(t) {} //Initializer list must be used
int getT() { return t; }
};
int main() {
Test t1(10);
cout<<t1.getT();
return 0;
}
Basically when data members are declared constant they have to have some value before the object is constructed Hence we use member initializer so that before the object is constructed the data member has some value.
in this program till the end the data member will have the same value
for real scenario:
For example you have to make a payroll program in which each employee has a first name and last name so you wouldn't want functions to accidentally modify their names so hence to prevent this you can keep them constant.
why do we define a variable as a const ?
A variable is declared const to indicate that it will not be changed.
but, when i come across initialization list for constructors, that allows to assign value to the const variable during object construction( i tried the below program for ex.), i'm confused with the basic concept of const keyword itself. can someone clarify this?
Is it not assignment but construction if it would be of not simple type but of MyClass, there constructor of MyClass would be used, not operator=
It does not change during the object-construction, because it has no (defined) value.
When you supply a const-member in a class, then this is a part of the object's identity and this particular value will stay the same through the object's life.
When declaring a member const you promise the compiler that you won't attempt to change the value of this member.
From MSDN
The const keyword specifies that a variable's value is constant and tells the compiler to prevent the programmer from modifying it.
// constant_values1.cpp
int main() {
const int i = 5;
i = 10; // C3892
i++; // C2105
}
I want to know why constant data member of a class need to be initialized at the constructor and why not somewhere else? What is the impact of doing so and not doing so?
I also see that only static constant integral data can be initialized inside the class other than that non of the data members can be initialized inside the class.
for eg:- Suppose below is my class declaration
class A{
int a; // This we can initialize at the constructor or we can set this member by calling "vSet" member function
const int b;
static const int c = 10; //This works fine
public:
A();
~A();
void vSet(int a);
int iAdd();
void vDisplay();
};
And the constructor is defined as mentioned below:-
Edited Section: As previous constructor definition example was wrong
A::A():a(1),b(9){}
Please correct me if I am wrong.
Thanks in advance.
A::A(){
a = 1;
b = 9; // Why we need to initialize this only at the constructor.
}
Is not initialization but it is Assignment.
a and b are already constructed and you assign them values in this case. The const qualifier demands that the variable not be changed after its initialization, allowing this assignment would break that contract.
This is Initialization using Member Initialization list.
A::A():a(1),b(9)
{}
You might want to have a look at this answer of mine to know the difference:
What is the difference between Initializing and Assignment inside constructor?
As for another question, regarding only static constant integral data can be initialized inside the class, please read this answer of mine which explains in greater detail:
Why I can't initialize non-const static member or static array in class?
What you're doing is not initialization. It is assignment, so b=9 will NOT even compile, because b is a const, so cannot be assigned any value to it. It should be initialized, and to do that, use member-initialization list as:
A::A() : a(1), b(9)
{ // ^^^^^^^^^^^^ this is called member-initialization list
}
In C++11, you can use in-place initialization as:
class A{
int a = 1; //C++11 only
const int b = 9; //C++11 only
static const int c = 10; //This works fine (both in C++03 and C++11)
//...
};
Because it is constant, it's value cannot be changed. Initializing anywhere else other than the constructor would mean a default initialization, followed by an assignment, which is not permitted for a constant. It would be the equivalent of doing this:
const int i; // OK
i = 42; // Error!
Note that in C++11 it is perfectly OK to do this:
struct Foo {
const int i=42;
const double x = 3.1416;
};
But this follows the same rules, i.e there is no assignment.
A const data is a data that can never be changed. It is initialized once, and then keeps the same value forever.
Because of that, you can't just assign a value to it anywhere.
The constructor, however, is where initialization goes. So here, there is an exception, and you are able to assign a value to your const data. You can do this the classical way, or as many said, as initialization list.
Now, why you can't do this in the class definition (unlike, say, Java) when the variable is not static is another problem, that I know no answer to.
When the body of your constructor is entered, all members and sub-objects are already initialized. The only thing the constructor body can do is to change them – and that is, obviously, not allowed for const members.
You can, however, use an initializer list.
You can't initialize const members outside of a constructor because, well, they're const. By definition, you can't modify them after they've been initialized, and after the object has been constructed, anything that tries to set the value is a modification.
const values are meant to be rvalues, so they cannot appear on the right part of an expression due its constness.
so, when you use this expression on the constructor's body
A::A()
{
a = 1;
b = 9; // Why we need to initialize this only at the constructor.
}
You're using the const value as a lvalue, just as Als mentioned before. The fact is that you're trying to assing a new value to a variable that isn't allowed to change it's value afther it's lifetime had begun.
The correct way to assign values to a constant data member is in the ctor initializer list, that is, BEFORE the lifetime of the member value begins (as mentioned by Nawaz):
A::A() :
a(1),
b(9)
{
}
Finally, on the C++11 standard you're allowed to initialize all data members where it was declared, just like the static const ones.
I wrote the following code snippet:
void foo()
{
struct _bar_
{
int a;
} bar;
cout << "Value of a is " << bar.a;
}
and compiled it with g++ 4.2.1 (Mac). The output is "Value of a is 0".
Is it true to say that data members of a struct in c++ are always initialized by default (compared to c)? Or is the observed result just coincidence?
I can imagine that structs in c++ have a default constructor (since a struct and a class is almost the same in c++), which would explain why the data member a of bar is initialized to zero.
The simple answer is yes.
It has a default constructor.
Note: struct and class are identical (apart from the default state of the accesses specifiers).
But whether it initializes the members will depends on how the actual object is declared. In your example no the member is not initialized and a has indeterminate value.
void func()
{
_bar_ a; // Members are NOT initialized.
_bar_ b = _bar_(); // Members are zero-initialized
// From C++14
_bar_ c{}; // New Brace initializer (Members are zero-initialized)
_bar_* aP = new _bar_; // Members are NOT initialized.
_bar_* bP = new _bar_(); // Members are zero-initialized
// From C++14
_bar_ cP = new _bar_{}; // New Brace initializer (Members are zero-initialized)
}
// static storage duration objects
// i.e. objects at the global scope.
_bar_ c; // Members are zero-initialized.
The exact details are explained in the standard at 8.5 Initializers [dcl.init] paragraphs 4-10. But the following is a simplistic summary for this situation.
A structure without a user defined constructor has a compiler generated constructor. But what it does depends on how it is used and it will either default initialize its members (which for POD types is usually nothing) or it may zero initialize its members (which for POD usually means set its members to zero).
PS. Don't use a _ as the first character in a type name. You will bump into problems.
Is it true to say that data members of a struct in c++ are always initialized by default (compared to c)? Or is the observed result just coincidence?
It is a coincidence.
Your code invokes Undefined Behavior; unless you explicitly set the members to 0 they can be anything.
Not an answer, but you might take it to be... if you want to try it:
void foo() {
struct test {
int value;
} x;
std::cout << x.value << std::endl;
x.value = 1000;
}
int main() {
foo();
foo();
}
In your example, the memory already had the 0 value before the variable was created, so you can call it a lucky coincidence (in fact, some OS will zero out all memory before starting a process, which means that 0 is quite a likely value to find in a small short program...), the previous code will call the function twice, and the memory from the first call will be reused in the second one, chances are that the second time around it will print 1000. Note however that the value is still undefined, and that this test might or not show the expected result (i.e. there are many things that the compiler can do and would generate a different result...)
Member variables of a struct are not initialized by default. Just like a class (because a struct is exactly the same thing as a class, only in struct the members are public by default).
Do not rely on this functionality it is non-standard
just add
foo() : a() {}
I can't remember the exact state of gcc 4.2 (i think it is too old) but if you were using C++11 you can do the following
foo()=default;
What EXACTLY is the difference between INITIALIZATION and ASSIGNMENT ?
PS : If possible please give examples in C and C++ , specifically .
Actually , I was confused by these statements ...
C++ provides another way of initializing member variables that allows us to initialize member variables when they are created rather than afterwards. This is done through use of an initialization list.
Using an initialization list is very similar to doing implicit assignments.
Oh my. Initialization and assignment. Well, that's confusion for sure!
To initialize is to make ready for use. And when we're talking about a variable, that means giving the variable a first, useful value. And one way to do that is by using an assignment.
So it's pretty subtle: assignment is one way to do initialization.
Assignment works well for initializing e.g. an int, but it doesn't work well for initializing e.g. a std::string. Why? Because the std::string object contains at least one pointer to dynamically allocated memory, and
if the object has not yet been initialized, that pointer needs to be set to point at a properly allocated buffer (block of memory to hold the string contents), but
if the object has already been initialized, then an assignment may have to deallocate the old buffer and allocate a new one.
So the std::string object's assignment operator evidently has to behave in two different ways, depending on whether the object has already been initialized or not!
Of course it doesn't behave in two different ways. Instead, for a std::string object the initialization is taken care of by a constructor. You can say that a constructor's job is to take the area of memory that will represent the object, and change the arbitrary bits there to something suitable for the object type, something that represents a valid object state.
That initialization from raw memory should ideally be done once for each object, before any other operations on the object.
And the C++ rules effectively guarantee that. At least as long as you don't use very low level facilities. One might call that the C++ construction guarantee.
So, this means that when you do
std::string s( "one" );
then you're doing simple construction from raw memory, but when you do
std::string s;
s = "two";
then you're first constructing s (with an object state representing an empty string), and then assigning to this already initialized s.
And that, finally, allows me to answer your question. From the point of view of language independent programming the first useful value is presumably the one that's assigned, and so in this view one thinks of the assignment as initialization. Yet, at the C++ technical level initialization has already been done, by a call of std::string's default constructor, so at this level one thinks of the declaration as initialization, and the assignment as just a later change of value.
So, especially the term "initialization" depends on the context!
Simply apply some common sense to sort out what Someone Else probably means.
Cheers & hth.,
In the simplest of terms:
int a = 0; // initialization of a to 0
a = 1; // assignment of a to 1
For built in types its relatively straight forward. For user defined types it can get more complex. Have a look at this article.
For instance:
class A
{
public:
A() : val_(0) // initializer list, initializes val_
{}
A(const int v) : val_(v) // initializes val_
{}
A(const A& rhs) : val_(rhs.val_) // still initialization of val_
{}
private:
int val_;
};
// all initialization:
A a;
A a2(4);
A a3(a2);
a = a3; // assignment
Initialization is creating an instance(of type) with certain value.
int i = 0;
Assignment is to give value to an already created instance(of type).
int i;
i = 0
To Answer your edited Question:
What is the difference between Initializing And Assignment inside constructor? &
What is the advantage?
There is a difference between Initializing a member using initializer list and assigning it an value inside the constructor body.
When you initialize fields via initializer list the constructors will be called once.
If you use the assignment then the fields will be first initialized with default constructors and then reassigned (via assignment operator) with actual values.
As you see there is an additional overhead of creation & assignment in the latter, which might be considerable for user defined classes.
For an integer data type or POD class members there is no practical overhead.
An Code Example:
class Myclass
{
public:
Myclass (unsigned int param) : param_ (param)
{
}
unsigned int param () const
{
return param_;
}
private:
unsigned int param_;
};
In the above example:
Myclass (unsigned int param) : param_ (param)
This construct is called a Member Initializer List in C++.
It initializes a member param_ to a value param.
When do you HAVE TO use member Initializer list?
You will have(rather forced) to use a Member Initializer list if:
Your class has a reference member
Your class has a const member or
Your class doesn't have a default constructor
Initialisation: giving an object an initial value:
int a(0);
int b = 2;
int c = a;
int d(c);
std::vector<int> e;
Assignment: assigning a new value to an object:
a = b;
b = 5;
c = a;
d = 2;
In C the general syntax for initialization is with {}:
struct toto { unsigned a; double c[2] };
struct toto T = { 3, { 4.5, 3.1 } };
struct toto S = { .c = { [1] = 7.0 }, .a = 32 };
The one for S is called "designated initializers" and is only available from C99 onward.
Fields that are omitted are automatically initialized with the
correct 0 for the corresponding type.
this syntax applies even to basic data types like double r = { 1.0
};
There is a catchall initializer that sets all fields to 0, namely { 0 }.
if the variable is of static linkage all expressions of the
initializer must be constant expressions
This {} syntax can not be used directly for assignment, but in C99 you can use compound literals instead like
S = (struct toto){ .c = { [1] = 5.0 } };
So by first creating a temporary object on the RHS and assigning this to your object.
One thing that nobody has yet mentioned is the difference between initialisation and assignment of class fields in the constructor.
Let us consider the class:
class Thing
{
int num;
char c;
public:
Thing();
};
Thing::Thing()
: num(5)
{
c = 'a';
}
What we have here is a constructor that initialises Thing::num to the value of 5, and assigns 'a' to Thing::c. In this case the difference is minor, but as was said before if you were to substitute int and char in this example for some arbitrary classes, we would be talking about the difference between calling a parameterised constructor versus a default constructor followed by operator= function.