Sign in to follow this  
johnnyBravo

Whats this strange code...c++

Recommended Posts

johnnyBravo    100
Hi, I'm learning about threads, and I've taken a look at ,this person's code. And they have this in it:
class Thread {
private:
    int running;
    unsigned long m_pid;
protected:
    Thread();
};

///this is the strange part.
Thread::Thread() 
    : running(0) 
    , m_pid(0L)
{
}


I've never seen that kind of syntax in c++ before, I guess it's just initializing the two variables, but why wouldn't you just do:
Thread::Thread() 
{
   running = 0;
   m_pid = 0L;
}


which is kind of cleaner. Thanks

Share this post


Link to post
Share on other sites
stylin    758
It's called an initialization list, and you should prefer to use that syntax rather than the one you posted, which assigns values to members after they have already been (default) initialized - usually a waste.

EDIT: some members can only be initialized in the initialization list, const and reference members to name two. linkified term

Share this post


Link to post
Share on other sites
Grafalgar    548
Exactly what stylin said. A little more detail:

When you instantiate an object, each of its members get constructed as well, meaning their constructors get called.

Initializing the members in the main object's constructor (in the second code listing) means the member's constructor gets called and then assignment operator is called.

The second code sample is the effectively the same as saying:
int a;
a = 0;

Most of the time the performance gain does not matter for large complex data structures, but for smaller objects that you'll have a LOT of temps flying around it'll really boost performance. Case in point : a custom 3D Vector class that's used all over a complex physics engine.

Personally I prefer to explicitly initialize the members in my constructor for complex data structures, even though this is not the 'preferred' method. It is, imo, a bit cleaner and easier to debug in certain cases. I only use the initialization list if I really need to squeeze performance out of something (like the custom vector I mentioned above).

Share this post


Link to post
Share on other sites
johnnyBravo    100
Quote:
Original post by Sharlin
Also, initializer lists are the only way to call a base class's constructor from a derived constructor.


I don't understand, can't you do:

DerivedConstructor::DerivedConstructor() {
BaseConstructor::BaseConstructor(); //call it from here.
}

Share this post


Link to post
Share on other sites
silencer-    223
Quote:
Original post by johnnyBravo
I don't understand, can't you do:
*** Source Snippet Removed ***

That will call the base ctor twice.

[edit:] I hadn't even noticed that you calling it as a static method. To correct myself: Calling the base constructor in a derived class outside the initializer list will result in the base ctor being called twice.

Share this post


Link to post
Share on other sites
Shannon Barber    1681
Quote:
Original post by johnnyBravo
Quote:
Original post by Sharlin
Also, initializer lists are the only way to call a base class's constructor from a derived constructor.


I don't understand, can't you do:
*** Source Snippet Removed ***



Nope, won't compile.

Share this post


Link to post
Share on other sites
johnnyBravo    100
Quote:
Original post by Shannon Barber
Quote:
Original post by johnnyBravo
Quote:
Original post by Sharlin
Also, initializer lists are the only way to call a base class's constructor from a derived constructor.


I don't understand, can't you do:
*** Source Snippet Removed ***



Nope, won't compile.


I just compiled this in visual c++ 2005 express edition beta 2:

class Base {
public:
Base(){}
};
class Derived:public Base {
public:
Derived(){Base::Base();}
};



Seems to work ok, is this what you meant?

Quote:
Original post by silencer-
Quote:
Original post by johnnyBravo
I don't understand, can't you do:
*** Source Snippet Removed ***

That will call the base ctor twice.


Yes I can see that.

Quote:
Original post by Sharlin
Also, initializer lists are the only way to call a base class's constructor from a derived constructor.


So what does this mean?, like in what situation would this be useful?

Thanks.

Share this post


Link to post
Share on other sites
silencer-    223
Quote:
Original post by johnnyBravo
So what does this mean?, like in what situation would this be useful?

Thanks.

Initializing using a custom constructor.

class Base
{
public:
Base(int num) { /* Do whatever */ } // This should only be called once.
};

class Derived : public Base
{
public:
Derived(int num) : Base(num) { } // Calls base ctor with int value.
};

Share this post


Link to post
Share on other sites
me22    212
Quote:
Original post by johnnyBravo
I don't understand, can't you do:
DerivedConstructor::DerivedConstructor() {
BaseConstructor::BaseConstructor(); //call it from here.
}


That will create a temporary BaseConstructor object, do nothing with it, and then get rid of it.

Note that the default constructor of BaseConstructor will still be called to initialise the base part of DerivedConstructor.

Share this post


Link to post
Share on other sites
Grafalgar    548
Quote:
Original post by me22
Quote:
Original post by johnnyBravo
I don't understand, can't you do:
DerivedConstructor::DerivedConstructor() {
BaseConstructor::BaseConstructor(); //call it from here.
}


That will create a temporary BaseConstructor object, do nothing with it, and then get rid of it.

Note that the default constructor of BaseConstructor will still be called to initialise the base part of DerivedConstructor.


Actually explicitly calling the constructor does not create any temporary objects :) Calling the constructor does not create the object, instead the constructor is called right after memory is allocated for an object.

So in this case the base constructor will be called twice : Once when the actual object's memory is allocated and the constructors are called implicitly, and once explicitly by the programmer in the body of the derived class' constructor.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Also note that primitive types (int, float, .. , all raw pointers) are NOT default initialized. There's no performance gain in using an initializer list to initialize them.

Share this post


Link to post
Share on other sites
dragongame    538
Hi,

the following should clear thinks up!

#include <iostream>

class Base
{
public:
Base() { std::cout << "Constructor of Base called\n"; }
~Base() { std::cout << "Destructor of Base called\n"; }
};

class Derived : public Base
{
public:
Derived()
{
Base::Base();
std::cout << "Derived Constructor called\n";
}
~Derived() { std::cout << "Derived Destructor called\n"; }
};

int main()
{
Derived d;

return 0;
}





gives me the following result:
Constructor of Base called
Constructor of Base called
Destructor of Base called

Derived Constructor called
Derived Destructor called
Destructor of Base called
which clearly shows that a temporary object is created!

Share this post


Link to post
Share on other sites
johnnyBravo    100
Quote:
Original post by Anonymous Poster
Also note that primitive types (int, float, .. , all raw pointers) are NOT default initialized. There's no performance gain in using an initializer list to initialize them.


But I might aswell initialize my pointers to 0 using the initializer list?

I usually set all up my pointers to 0, so iI can just check if they are not 0(pointing to something) so I can delete them if required.

Share this post


Link to post
Share on other sites
dragongame    538
Yes you can do that, or even should do that.
But try to use NULL or 0L because pointer are of type long int which is different than a normal int on (some) 64-Bit Machines.

Share this post


Link to post
Share on other sites
helix    301
That is required by the style convention at my job so I started using it. I used to think it was much cleaner to just initialize them inside the constructor but now I'm sold on the initializer list and will not go back.

Share this post


Link to post
Share on other sites
Fruny    1658
Quote:
Original post by johnnyBravo
I just compiled this in visual c++ 2005 express edition beta 2:

class Base {
public:
Base(){}
};
class Derived:public Base {
public:
Derived(){Base::Base();}
};


Seems to work ok, is this what you meant?


That creates an unnamed temporary local variable of type Base within the body of Derived's constructor. That variable is destroyed at the end of the statement that created it.

It is not a 'call to the constructor'.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Quote:
Original post by johnnyBravo
But I might aswell initialize my pointers to 0 using the initializer list?
Yeah, whatever you prefer. Makes no difference to resulting executable code.
Quote:
I usually set all up my pointers to 0, so iI can just check if they are not 0(pointing to something) so I can delete them if required.
You don't need to check if they are 0. 0-pointers can be deleted safely (i.e. the delete won't do anything if the pointer points to 0)



Quote:
Original post by dragongame
But try to use NULL or 0L because pointer are of type long int which is different than a normal int on (some) 64-Bit Machines.
At least Stroustrup recommends using 0, and I'd rather believe him than you :)
http://www.research.att.com/~bs/bs_faq2.html#null

Share this post


Link to post
Share on other sites
johnnyBravo    100
Quote:
Original post by Anonymous Poster

Quote:
Original post by dragongame
But try to use NULL or 0L because pointer are of type long int which is different than a normal int on (some) 64-Bit Machines.
At least Stroustrup recommends using 0, and I'd rather believe him than you :)
http://www.research.att.com/~bs/bs_faq2.html#null


Ok, I'll use 0 then.

Share this post


Link to post
Share on other sites
Roboguy    794
Another thing that you can do this with initialization list:

// ... Header ...
class Example {
int test;
public:
Example(int test);
};

// ... Implementation file ...
Example::Example(int test)
: test(test) { }


This will assign the value of the test argument given to the constructor to the test property of the object.

Share this post


Link to post
Share on other sites
johnnyBravo    100
Quote:
Original post by Roboguy
Another thing that you can do this with initialization list:

// ... Header ...
class Example {
int test;
public:
Example(int test);
};

// ... Implementation file ...
Example::Example(int test)
: test(test) { }


This will assign the value of the test argument given to the constructor to the test property of the object.


Yeah I worked that out, its pretty cool, instead of having to do the old this->test= test

Share this post


Link to post
Share on other sites
dragongame    538
Hi,

on an Alpha Machine an int is 32-bit and a pointer is 64 bit.
o is of type int. I use 0L because when you know what type a pointer is, you should compare with the same type!
So compiler will like make a 0 to 0L anyway, but why not do it in the first place.
And people often cast pointers to int, which will make a program not run on a 64-bit machine.

Share this post


Link to post
Share on other sites
Extrarius    1412
dragongame: Pointers are a unique type, and are not the same as any other type. 0 is a special value and is not the same as any literal number because when you convert 0 to a pointer, it MUST become a null pointer, and two null pointers must compare equal.

Note that null pointer and 0 are not the same thing. A 0 becomes a null pointer when converted to a pointer type, but a null pointer can become any value when you convert it to any non-pointer type.

It is perfectly valid for:
void *Pointer = 0;
if(unsigned long(Pointer) == 0)
{
cout << "Pointer is 0";
}
else
{
cout << "Pointer is not 0";
}
to print out "Pointer is not 0" because converting a null pointer to an integer is not required to evaluate to 0. The special conversion of 0 is only guaranteed one way (from 0 to null pointer) and the reason comparing a pointer to 0 works is that the only valid automatic conversion is to convert the 0 to a pointer of the same type (so it becomes a null pointer) and then after the conversion the null pointer is compared with your pointer variable.

Casting a pointer to any non-pointer type is not guaranteed to work no matter what integer type you use, except in C where there is a "intptr_t" type defined so that you can convert a void pointer to intptr_t then back to a void pointer and it will have the same value, but there is still no guarantee about what the value will be, or that if you add 1 to the intptr_t that it would point to the next byte, or anything like that. Converting pointers to integers only works because the major vendors decided it should. Counting on such behavior makes a program non-standard.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this