I am learning about inheritance in C++. And i came across the following statement:
In other words, the this pointer cannot be aliased in a constructor:
extern struct D d;
struct D
{
D(int a) : a(a), b(d.a) {} // b(a) or b(this->a) would be correct
int a, b;
};
D d = D(1); // because b(d.a) did not obtain a through this, d.b is now unspecified
The above example is from cppreference.
My first question is that it is written that "this cannot be aliased in a ctor" but then in the example above, they've written in the comment "b(this->a) would be correct". This seems to be a contradiction to me because when they said that this cannot be aliased in a ctor i understood that "this cannot be used in a ctor". But then why are they saying that writing b(this->a) would be correct if this cannot be used/aliased in a ctor. Isn't the initializer list considered "in a ctor"?
Now lets look at a custom example:
struct Name
{
private:
int x = 0;
Name(int n )
{
this->x = 4; //is the use of "this" well-defined here?
}
};
My second question is that is the use of the expression this->x inside the converting constructor shown above well-defined? I mean since according the quote at the beginning of my question this can't be aliased in a ctor, so this shouldn't be valid.
What is meant is that during the construction of a class object any access to the object's non-static data members should happen through a pointer/glvalue obtained directly or indirectly from this of the constructor. Otherwise the value read by such an access is unspecified.
So this->a is always fine, as is simply a which is implicitly the same as this->a.
It is also ok to copy the pointer this and access members through that, e.g.
auto p = this;
b = p->a;
or to store a reference to the object:
auto& r = *this;
b = r.a;
But in the example given at the beginning, d is the same object as this points to. In other words the name d and *this are aliases for the same object. It is not allowed to use this other alias d to access non-static data members of the class while it is under construction because d was not obtained from this. Or to be more precise, it is unspecified what value such an access will read. So b(d.a) may or may not initialize the b member to the same value as a.
See [class.cdtor]/2.
Related
Hey this is a really basic question and but I got confused about it. Say I created an object
MyObject a.
It comes with a copy constructor, so I know I can do this:
MyObject b(a);
But can I do this?
MyObject& b(a);
And if I do this:
MyObject b = a; what is in b? Apology if this question is too fundamental to be bothered posting.
Doing MyObject& b(a) has nothing to do with the copy constructor. It just creates b which is a reference to the object a. Nothing is copied. Think of b as an alias for the object a. You can use b and a equivalently from then on to refer to the same object.
MyObject b = a; will use the copy constructor, just as MyObject b(a); would.
There are two forms of initialisation: T x = a; is known as copy-initialization; T x(a) and T x{a} are known as direct-initialization.
When T is a reference type, it doesn't matter which type of initialisation is used. Both have the same effect.
When T is a class type, we have two possibilities:
If the initialisation is direct-initialization (MyClass b(a);), or, if it is copy-initialization with a being derived from or the same type as T (MyClass b = a;): an applicable constructor of T is chosen to construct the object.
As you can see, both of your examples fall in this category of class type initialisers.
If the initialisation is any other form of copy-initialization, any user-defined conversion sequence will be considered followed by a direct-initialization. A user-defined conversion sequence is basically any sequence of standard conversions with a single conversion constructor thrown in there.
If c were of Foo class type and there was a conversion constructor from Foo to MyClass, then MyClass b = c; would be equivalent to MyClass b(MyClass(c));.
So basically, if the source and destination types are the same, both forms of initialisation are equivalent. If a conversion is required, they are not. A simple example to show this is:
#include <iostream>
struct Bar { };
struct Foo
{
Foo(const Foo& f) { std::cout << "Copy" << std::endl; }
Foo(const Bar& b) { std::cout << "Convert" << std::endl; }
};
int main(int argc, const char* argv[])
{
Bar b;
Foo f1(b);
std::cout << "----" << std::endl;
Foo f2 = b;
return 0;
}
The output for this program (with copy elision disabled) is:
Convert
----
Convert
Copy
Of course, there are lots of other types of initialisations too (list initialisation, character arrays, aggregates, etc.).
Here is my view:
References are tied to someones else's storage, whenever u access a reference, you’re accessing that storage. References cannot be assigned to null because of the fact that they are just an aliases. A reference must be initialized when it is created. (Pointers can be initialized at any time.)
so when you say
MyObject& b(a);
compiler allocates a piece of storage b, and ties the reference to a.
when you say
MyObject b = a;
you pass a reference of a to the copy constructor and creates new b from it. Note that its a deep copy only if you have a copy constructor written for it. Otherwise it calls the default copy constructor which results in a shallow copy.
and when you say
a = b; // after creating these objects
it translates as Object::operator=(const Object&), thus A.operator=(B) is called (invoke simple copy, not copy constructor!)
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.
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.
I found the following snippet in the C++03 Standard under 5.3.5 [expr.delete] p3:
In the first alternative (delete object), if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the operand’s dynamic type and the static type shall have a virtual destructor or the behavior is undefined. In the second alternative (delete array) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined.
Quick review on static and dynamic types:
struct B{ virtual ~B(){} };
struct D : B{};
B* p = new D();
Static type of p is B*, while the dynamic type of *p is D, 1.3.7 [defns.dynamic.type]:
[Example: if a pointer p whose static type is “pointer to class B” is pointing to an object of class D, derived from B, the dynamic type of the expression *p is “D.”]
Now, looking at the quote at the top again, this would mean that the follwing code invokes undefined behaviour if I got that right, regardless of the presence of a virtual destructor:
struct B{ virtual ~B(){} };
struct D : B{};
B* p = new D[20];
delete [] p; // undefined behaviour here
Did I misunderstand the wording in the standard somehow? Did I overlook something? Why does the standard specify this as undefined behaviour?
Base* p = new Base[n] creates an n-sized array of Base elements, of which p then points to the first element. Base* p = new Derived[n] however, creates an n-sized array of Derived elements. p then points to the Base subobject of the first element. p does not however refer to the first element of the array, which is what a valid delete[] p expression requires.
Of course it would be possible to mandate (and then implement) that delete [] p Does The Right Thing™ in this case. But what would it take? An implementation would have to take care to somehow retrieve the element type of the array, and then morally dynamic_cast p to this type. Then it's a matter of doing a plain delete[] like we already do.
The problem with that is that this would be needed every time an array of polymorphic element type, regardless of whether the polymorphism is used on not. In my opinion, this doesn't fit with the C++ philosophy of not paying for what you don't use. But worse: a polymorphic-enabled delete[] p is simply useless because p is almost useless in your question. p is a pointer to a subobject of an element and no more; it's otherwise completely unrelated to the array. You certainly can't do p[i] (for i > 0) with it. So it's not unreasonable that delete[] p doesn't work.
To sum up:
arrays already have plenty of legitimate uses. By not allowing arrays to behave polymorphically (either as a whole or only for delete[]) this means that arrays with a polymorphic element type are not penalized for those legitimate uses, which is in line with the philosophy of C++.
if on the other hand an array with polymorphic behaviour is needed, it's possible to implement one in terms of what we have already.
It's wrong to treat an array-of-derived as an array-of-base, not only when deleting items. For example even just accessing the elements will usually cause disaster:
B *b = new D[10];
b[5].foo();
b[5] will use the size of B to calculate which memory location to access, and if B and D have different sizes, this will not lead to the intended results.
Just like a std::vector<D> can't be converted to a std::vector<B>, a pointer to D[] shouldn't be convertible to a B*, but for historic reasons it compiles anyway. If a std::vector would be used instead, it would produce a compile time error.
This is also explained in the C++ FAQ Lite answer on this topic.
So delete causes undefined behavior in this case because it's already wrong to treat an array in this way, even though the type system can't catch the error.
Just to add to the excellent answer of sth - I have written a short example to illustrate this issue with different offsets.
Note that if you comment out the m_c member of the Derived class, the delete operation will work well.
Cheers,
Guy.
#include <iostream>
using namespace std;
class Base
{
public:
Base(int a, int b)
: m_a(a)
, m_b(b)
{
cout << "Base::Base - setting m_a:" << m_a << " m_b:" << m_b << endl;
}
virtual ~Base()
{
cout << "Base::~Base" << endl;
}
protected:
int m_a;
int m_b;
};
class Derived : public Base
{
public:
Derived()
: Base(1, 2) , m_c(3)
{
}
virtual ~Derived()
{
cout << "Derived::Derived" << endl;
}
private:
int m_c;
};
int main(int argc, char** argv)
{
// create an array of Derived object and point them with a Base pointer
Base* pArr = new Derived [3];
// now go ahead and delete the array using the "usual" delete notation for an array
delete [] pArr;
return 0;
}
IMHO this has to do with limitation of arrays to deal with constructor/destructor. Note that, when new[] is called, compiler forces to instantiate only default constructor. In the same way when delete[] is called, compiler might look for only the destructor of calling pointer's static type.
Now in the case of virtual destructor, Derived class destructor should be called first followed by the Base class. Since for arrays compiler might see the static type of calling object (here Base) type, it might end up calling just Base destructor; which is UB.
Having said that, it's not necessarily UB for all compilers; say for example gcc calls destructor in proper order.
I think it all comes down to the zero-overhead principle. i.e. the language doesn't allow storing information about the dynamic type of elements of the array.
Just a simple question about c++ coding style,
for example, all member variables of a class will be called with the default constructor in the initialization list if we don't do anything else. B default constructor will be called and value will be set to 0, int();
class A
{
A();
private:
B b;
int value;
}
However my question is, even do the default constructor will be called is it a good habit to always do it yourself or does it only add extra lines to the code
A::A() : b(), value() {}
You are touching on one of the sticky corners of C++.
The initialization of POD values in objects is sticky and depends on a few things.
Even I am not sure I can get all the rules correct but I believe #Steve Jessop once wrote an article about here on SO (though I can currently find it).
But some examples:
This class will always be initialized b == false and value = 0.
class A
{
A() : b(), value() {}
B b;
int value;
};
Without an explicit default constructor it is more complex:
Here the compiler will generate a default constructor for you. But how the compiler generated default constructor works depends on the situation. The compiler generated default constructor can do two different forms of initialization and which is used depends on context:
Zero Initialization (All POD members are zero'ed out)
Value Initialization (All POD members are left undefined)
Example:
class B
{
B b;
int value;
};
// Variables of static storage duration (notably globals)
// Will be zero initialized and thus b == false and value = 0
B global; // Initialized
int main()
{
// Object of automatic storage duration or dynamic storage duration
// These will depend on how they are declared.
// Value Initialization (POD re-mains undefined)
B bo1; // b/value undefined
B* bp1 = new B; // b.balue undefined
// Zero Initialization
B bo2 = B(); // b = false, value = 0
B* bp2 = new B(); // b = false, value = 0
// Note: The most obvious syntax for zero initializing a local object
// does not work as it is actually interpreted as a forward
// declaration of a function;
B bo3();
}
It's a good idea to leave the default constructor out. The compiler-generated constructors are much more reliable and maintainable than writing your own versions, and apart from anything else, it's a flat out waste of time to write code the compiler could write for you. If you don't need any construction logic, then don't write a constructor.
However, the int will not be initialized unless you do it, which is a sucky reason to have to write a constructor.
By default int variables are not initialized with a value - you have to do it yourself.
So when you don't set the member variable "value" to some value in the constructor it is left uninitialized.
The default constructor will only be called for class types with default constructors, not for primitives.