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.
Related
I've been programming C++ for decades and never expected this limitation.
Is there something obvious I'm overlooking? I guess I need to make the X() constructor take an argument for i and let that constructor initialize it? What can the point of this weird limitation possibly be? I can understand forbidding us from initializing an object twice, but it's not initialized at all! (Or, I guess in the absence of an explicit constructor, X's constructor will give it a default initialization?) And yet:
class X {
public:
X() {};
int i;
};
class X1 : public X {
public:
X1() : i(1){};
};
results in error:
initial.cpp: In constructor 'X1::X1()':
initial.cpp:11:10: error: class 'X1' does not have any field named 'i'
X1() : i(1){};
^
That's meant to be as initialization of object is a part of that objects creation, you either have to provide initialization via X, or redesign to be able initialize it directly:
class X {
public:
X() {};
X(int _i) : i(_i) {};
int i;
};
or
class X {
public:
int i;
};
so you can do this:
class X1 : public X {
public:
X1() : X{1}{};
};
Allowing what you tried to do would imply that we had to insert a new initialization behavior into existing sequence, which could be compiled already as part of different compilation unit or to allow that member be initialized twice. Former is problematic to implement with whole concept of C++ implementation as native compilers, the latter makes sequence of initialization non-linear and contradicting existing ideology.
Note, that usually composition is preferable to inheritance if you target storage area instead of behaviour, i.e.
InterfaceX {
// declarations to be used in descendants
};
class X1 : public InterfaceX
{
X m_x;
public:
X1() : m_x{1} {};
};
If we actually require polymorphic use, we'd use InterfaceX for virtual methods. And if we would need to "cut down" X1 to X, there need to be an conversion operator operator X () {return m_x; }
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.
Suppose I have a class Baz that inherits from classes Foo and Bar, in that order. The constructor for class Bar takes a pointer to a Foo object. What I would like to do is to pass this as the Foo object to the Bar constructor:
Baz () : Foo(), Bar(this) {}
A working example:
#include <iostream>
class Bar;
class Foo {
public:
virtual ~Foo() {}
virtual void parse_bar (Bar&) const = 0;
};
class Bar {
private:
const Foo * parser;
public:
Bar (const Foo * parser_in) : parser(parser_in) {}
virtual ~Bar() {}
void parse_self () { parser->parse_bar (*this); }
};
class Baz : public Foo, public Bar {
public:
Baz () : Foo(), Bar(this) {}
virtual void parse_bar (Bar &) const { std::cout << "Hello World\n"; }
};
int main () {
Baz baz;
baz.parse_self();
}
This happens to work on my computer, with my compilers (tested with a couple of them). However section 9.3.2 of the 2003 standard makes me a bit uneasy that I might just be getting lucky, that using this this way is undefined behavior. Strictly speaking, the initializer list is outside the body of the constructor. Here's the relevant text, emphasis mine:
9.3.2 The this pointer
In the body of a nonstatic member function, the keyword this is a non-lvalue expression whose value is the address of the object for which the function is called.
So is my usage legal and well-defined, or is it undefined behavior?
There are two points that have to be noted in this case.
Firstly, in the constructor initializer list this pointer refers to a non-constructed (or not-fully-constructed) object. It is OK to access such pointer, but the object it refers to can only be used in limited ways. See 12.7 in the language specification.
Secondly, in your specific example what you are actually doing is converting this pointer to Foo * type before attempting any access. This is completely safe since by that moment the Foo subobject is fully constructed. (I assume that, whatever access will follow, if any, will be restricted only to the fully constructed Foo subobject).
The only concern is this case is whether it is legal to convert this to Foo * type, i.e. whether the conversion process itself should succeed. The answer is: yes, in case of ordinary (non-virtual) inheritance such conversion is perfectly legal and safe (again, explicitly allowed in 12.7)
It is fine. The C++ standard actually clarifies the use of this pointers in initializer lists:
12.6.2 Initializing bases and members [class.base.init]
Paragraph 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. ]
The type of the this pointer in the initializer of Baz is in fact of type Baz. Of course, you have to be mindful of the fact that not all of the members may have been initialized. Many, if not all, compilers set at their highest warning levels (which you really should be doing anyway) will warn about you passing a this pointer to the base class.
However, it looks like you're making it more complicated that it needs to be. Why not just put the virtual function parse_bar() in the Bar class, and forget about the Foo class?
#include <iostream>
class Bar
{
public:
Bar() {}
virtual ~Bar() {}
void parse_self () { parse_bar(); }
private: // Template method pattern
virtual void parse_bar() const = 0;
};
class Baz : public Bar
{
public:
Baz () {}
private: // Yes, this does override the private `parse_bar()` member!
virtual void parse_bar() const { std::cout << "Hello World\n"; }
};
int main ()
{
Baz baz;
baz.parse_self();
}
This does essentially the same function but with less code.
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!
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.