Passing 'this' within braces to an object of a class in C++ - c++

class District
:public State<District>
{
public:
typedef Citizen Man;
using State<District>::State;
void CheckTransition( Man& Man );
private:
int counter = 0;
};
class Citizen
:public TopState<Citizen>
{
public:
Citizen();
District object{this};
};
I am unable to understand the usage of the last line in this piece. Can some one please explain what is happening here?
Line: District object{this};
I would like to understand the usage of this in this context within the braces to an object of a class.

Line: District object{this};
I would like to understand the usage of 'this' in this context within the braces to an object of a class.
A new way of initialization called brace-initialization was introduced in C++11 which makes the following possible:
int z{ 0 };
std::vector<int> v{ 1, 3, 5 };
Widget w1{10};
Widget w2{w1};
And it is also possible to use this for initialization.
From the standard 12.6.2/7 "Initializing bases and members" available here:
12.6.2 Initializing bases and members [class.base.init]
....
7 Names in the expression-list of a mem-initializer are evaluated in the scope of the constructor for which the mem-initializer is specified.
[Example:
class X {
int a;
int b;
int i;
int j;
public:
const int& r;
X(int i): r(a), b(i), i(i), j(this->i) {}
};
initializes X::r to refer to X::a, initializes X::b with the value of the constructor parameter i, initializes X::i with the value of the constructor parameter i, and initializes X::j with the value of X::i; this takes place each time an object of class X is created. ]
[Note: because the mem-initializer are evaluated in the scope of the constructor, the this pointer can be used in the expression-list of a mem-initializer to refer to the object being initialized. ]
It's safe to use this pointer in initialization-list as long as it's not being used to access uninitialized members or virtual functions.

Related

Constructor in the parent class doesn't assign the value to a private variable

This is my code and you can also run it from http://cpp.sh/5lsds
#include "iostream"
using namespace std;
class X{
private:
int c;
public:
X(){}
X(int b){
c = 11;
}
int getC();
};
class Z:public X{
public:
Z(int n){
X(23);
}
};
int main()
{
Z z(1);
cout<<z.getC()<<endl;
return 0;
}
int X::getC(){
return c;
}
I need to have X(){} line since the child constructor needs to call the parent default constructor.
If you run the program from http://cpp.sh/5lsds you can see that the output is 0 while I expect it to be 11. Since the Z constructor calls X constructor with an int parameter and it sets the c value to 11 but the output is 0.
You should use member initializer list,
In the definition of a constructor of a class, member initializer list specifies the initializers for direct and virtual base subobjects and non-static data members.
e.g.
Z(int n) : X(23) {}
I need to have X(){} line since the child constructor needs to call the parent default constructor.
With member intializer list it's not required again (in this code sample).
For X(23); in the body of the constructor, you're just creating a temporary X, which has nothing to do with the base subobject X of Z; Then the default constructor of X (i.e. X::X()) will be used for it. i.e. it's equivalent with:
Z(int n) : X() { // initialize the base suboject X via X::X()
X(23); // create an unnamed temporary via X::X(int)
}
You don't invoke the constructor of the base class
Z(int n){
X(23);
}
This creates an unnamed temporary X object, and passes 23 to its constructor. It doesn't construct the X sub-object of Z.
In C++, we construct bases and members using the member initializer list syntax:
X(int b) :
c(11)
{}
Z(int n) :
X(23)
{}
The member initializer list syntax is pretty much equivalent to the assignment you do when a simple integer is the constructed member. But beware that more complex sub-objects will be default constructed first, and then have their assignment operator invoked. That could make a substantial (worsening) difference in performance to just specifying them in the member initializer list and constructing once.

Method as an argument of base class constructor in subclass constructor [duplicate]

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.

Access member field with same name as local variable (or argument)

Consider following code snippet:
struct S
{
S( const int a )
{
this->a = a; // option 1
S::a = a; // option 2
}
int a;
};
Is option 1 is equivalent to option 2? Are there cases when one form is better than another? Which clause of standard describes these options?
option 1 is equivalent to option 2, but option 1 will not work for a static data member
EDITED: static data members can be accessed with this pointer. But this->member will not work in static function. but option 2 will work in static function with static member
Eg:
struct S
{
static void initialize(int a)
{
//this->a=a; compilation error
S::a=a;
}
static int a;
};
int S::a=0;
Have you tried this option?
struct S
{
S(int a) : a(a) { }
int a;
};
Have a look at the following:
12.6.2 Initializing bases and members
[12] Names in the expression-list or braced-init-list of a mem-initializer are evaluated in the scope of the constructor for which the mem-initializer is specified. [ Example:
class X {
int a;
int b;
int i;
int j;
public:
const int& r;
X(int i): r(a), b(i), i(i), j(this->i) { }
};
initializes X::r to refer to X::a, initializes X::b with the value of the constructor parameter i, initializes X::i with the value of the constructor parameter i, and initializes X::j with the value of X::i; this takes place each time an object of class X is created. — end example ] [ Note: Because the mem-initializer are evaluated in the scope of the constructor, the this pointer can be used in the expression-list of a mem-initializer to refer to the object being initialized. — end note ]
Both forms are identical unless a is a virtual function. I'd
prefer this->a, because it does what I usually want even if
a is a virtual function. (But isn't it better to avoid the
name clash to begin with.)

can member functions be used to initialize member variables in an initialization list?

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.

In C++, initialize a class member with 'this' pointer during construction

I'd like to create a class that is associated to another class in some sort of parent-child relationship. For this the "child" class needs a reference to it's parent.
For example:
template <typename T>
class TEvent {
private: T* Owner;
public: TEvent(T* parent) : Owner(parent) {}
};
class Foo {
private: TEvent<Foo> Froozle; // see below
};
Now the problem is that I can't initialize the Froozle instance directly, nor using the instanciation list of Foo's constructor, because this references are not allowed there. Apart from adding another method setParent(T*) (which I don't like too much because it means that I have to leave the TEvent<> instance in an invalid state), is there a way to achieve this?
It is OK to use this in the initialization list, as long as it is not used to access any members that may not have been initialized yet.
From the standard 12.6.2/7 "Initializing bases and members" (emphasis mine):
Names in the expression-list of a
mem-initializer are evaluated in the
scope of the constructor for which the
mem-initializer is specified.
[Example:
class X {
int a;
int b;
int i;
int j;
public:
const int& r;
X(int i): r(a), b(i), i(i), j(this->i) {}
};
initializes X::r to refer to X::a,
initializes X::b with the value of the
constructor parameter i, initializes
X::i with the value of the
constructor parameter i, and
initializes X::j with the value of
X::i; this takes place each time an
object of class X is created. ]
[Note: because the mem-initializer are
evaluated in the scope of the
constructor, the this pointer can
be used in the expression-list of
a mem-initializer to refer to the
object being initialized. ]
This is supposed to work; in fact,
template<class T>
class Child {
private:
T *parent;
public:
Child(T *parent) : parent(parent) {}
};
class Parent {
private:
Child<Parent> child;
public:
Parent() : child(this) {}
};
compiles fine for me with both g++ 4.4.5 and clang++ 2.8.
What is failing for you?
I don't think it's failing on you, unless you have the warning level set to 4 (or similar, I assume Visual Studio) and have enabled "treat warnings as errors".
Basically, this warning is A Good Thing, since it won't let you accidentally use the this pointer when what it points at is yet to be constructed.
However, when you know what you are doing wherever this is passed in the initialization list, the warning and error caused by this will be annoying.
You can get rid of it (again, assuming Visual Studio) by decorating the constructor (unless it's defined in the class declaration - then you must decorate all the class):
// warning C4355: 'this' : used in base member initializer list
#pragma warning (push)
#pragma warning (disable : 4355)
some_class::some_class()
: ...
{
}
#pragma warning (pop)
If you're looking to suppress the warning, just do this:
class Foo
{
public:
Foo() :
Froozle(get_this())
{}
private:
Foo* get_this()
{
return this;
}
TEvent<Foo> Froozle; // see below
};
The indirection is enough to stop it.