|
-
October 1st, 2005, 07:53 PM
#1
constructor() : variable() {} <- what does it do?
I was reading up on the Half Life 2 SDK when I saw something I've never seen before.
Code:
class CMyLogicalEntity : public CLogicalEntity
{
public:
DECLARE_CLASS(CMyLogicalEntity, CLogicalEntity);
DECLARE_DATADESC();
CMyLogicalEntity(void) : m_nCounter(0) {}
void InputTick(inputdata_t &inputData);
private:
int m_nThreshold;
int m_nCounter;
COutputEvent m_OnThreshold;
};
It has this class, which I know classes, but I don't know what this does:
Code:
CMyLogicalEntity(void) : m_nCounter(0) {}
what is that colon( there for, what does it do when you put that there?
-
October 1st, 2005, 08:00 PM
#2
Re: constructor() : variable() {} <- what does it do?
It signifies an initializer list. These two are the same:
Code:
CMyLogicalEntity(void) : m_nCounter(0) {}
CMyLogicalEntity(void) { m_nCounter(0); }
However:
1) Stylistically, initializer lists are better
2) Initializer lists can initialize references and const objects
I hope this helped and my information was somewhat correct
-
October 2nd, 2005, 12:00 AM
#3
Re: constructor() : variable() {} <- what does it do?
I got this from this forum itself
Member variables can be initialized by:
Code:
CFoo::CFoo()
{
m_iMemberOne = 0;
m_iMemberTwo = 1;
}
or
CFoo::CFoo() : m_iMemberOne(0), m_iMemberTwo(1) { }
Technically spoken the second method (which is called member initialization list) is preferrable but in most cases it makes no difference. Mainly there are two reasons why:
Necessity
Let's assume that your class have a member variable which is itself a class and this class only has one constructor that requires an argument:
Code:
class CAnotherFoo
{
public:
CAnotherFoo(int iValue) { ... } // Explicit constructor therefore no default constructor
};
class CFoo
{
CAnotherFoo m_MemberOfTypeClass;
};
In this case the only way to initialize an instance of the member class 'm_MemberOfTypeClass' is by passing an integer to its constructor. The only possibility to do this is by using the member initialization list.
Code:
CFoo::CFoo() : m_MemberOfTypeClass(5) { ... }
That is the only way to pass the argument to the member class 'm_MemberOfTypeClass'. The same would apply if the member is a 'const' object or a reference. According to the standard, 'const' objects and references can only be initialized but not assigned.
Efficiency
Let's assume that your class have a member variable which is itself a class and this class has an overriden assignment operator ('CString' from the MFC is a simple example):
Code:
class CFoo
{
CString m_String;
}
If you want to initialize the contained 'CString' you have two possibilities:
1. Assigning it within the constructor
Code:
CFoo::CFoo()
{
m_String = "Hello World";
}
2. Via initialization list
Code:
CFoo::CFoo() : m_String("Hello World") { ... }
Even if it does not look like there are some major differences between both examples. The compiler will always insure that all member objects are initialized before the body of the constructor executes. The first example therefore will first call the default constructor of 'CString' to initialize 'm_String' before the control reaches the assignment operator. In the second example, the compiler would call a different constructor of 'CString' which takes a 'LPCTSTR' as an argument. As you can see the first example will generate two function calls (constructor and assignment operator) while the second one only will need one (constructor).
In the case of 'CString' it doesn't matter much since the default constructor is inline and memory gets allocated dynamically. But if you would have a class where both the constructor and the assignment operator would call the same 'Init()' function which allocates some memory you have no other choice but to use the member initialization list to avoid unnecessary allocation of memory.
If you are dealing with the standard type like 'int' etc. you won't notice any performance difference between assigning it within the constructor or with the initialization list since there will be always one assignment.
While dealing with initialization lists you should always keep one thing in mind. According to the standard class members get initialized in the order they are declared not in the order they appear in the initialization list...
Code:
class CFoo
{
public:
CFoo(int iValueOne, int iValueTwo);
private:
int m_iValueOne;
int m_iValueTwo;
};
CFoo::CFoo(int iValueOne, int iValueTwo) : m_iValueTwo(iValueTwo), m_iValueOne(iValueOne) { ... }
In this case 'm_iValueOne' gets initialized first although 'm_iValueTwo' is standing first within the initialization list. That standard behaviour can cause problems which are hard to find... To avoid this you should always use the same order at declaration and initialization time...
Appreciate others by rating good posts
"Only buy something that you'd be perfectly happy to hold if the market shut down for 10 years." - Warren Buffett
-
October 2nd, 2005, 05:16 AM
#4
Re: constructor() : variable() {} <- what does it do?
Initializer list is indispensable for following cases:
- The class contains one or more non-static constant variables.
- The class contains one or more reference type variables.
- The class is deriving from a base class which does not have default constructor. That is base class is requiring one or more argument to its constructor.
- The class has a instance variable of another class, that also holds point (3).
1 and 2 are striaghtforward to understand. Let me clear (3):
Code:
class CBase
{
public:
int x;
CBase(int y)
{
x=y;
}
... // No zero argument ctor
};
class CDerived : public CBase
{
CDerived() : CBase(10) // or anyother expression than '10'
}
If you do not pass "CBase(10)", the compiler will report error.
And (4):
Code:
CStr
{
public:
CStr(const char*)
{
// wharever code to intialize
}
CStr(int ) // convert from 'int'
{
// wharever code to intialize
}
... // Again, No zero argument ctor
};
class CUsage
{
CStr s1, s2;
public:
CUsage();
};
CUsage::CUsage() : s1("CodeGuru"), s2(1998)
-
October 2nd, 2005, 05:23 AM
#5
Re: constructor() : variable() {} <- what does it do?
 Originally Posted by sunnypalsingh
In the case of 'CString' it doesn't matter much since the default constructor is inline and memory gets allocated dynamically. But if you would have a class where both the constructor and the assignment operator would call the same 'Init()' function which allocates some memory you have no other choice but to use the member initialization list to avoid unnecessary allocation of memory.
Nope. This is not correct.
Even if you use initializer list to intialize CString (or other class object) this way, the constructor will anyhow be called. There are no performance penalties using or not using the initializer list.
Let us assume your description is correct. But I want to store the passed string into tree with some complex algorithm or to save it in map or something like that. How the compiler would do the same task if it cannot call constructor?
-
October 2nd, 2005, 07:32 AM
#6
Re: constructor() : variable() {} <- what does it do?
Posted by sunnypalsingh:
Code:
CFoo::CFoo()
{
m_iMemberOne = 0;
m_iMemberTwo = 1;
}
or
CFoo::CFoo() : m_iMemberOne(0), m_iMemberTwo(1) { }
Technically spoken the second method (which is called member initialization list) is preferrable but in most cases it makes no difference.
Actually it does make difference. The second case, using initialization list has better performance im most of the cases. On the 1st case the = operator is called, and on the 2nd it is not called.
-
October 2nd, 2005, 07:37 AM
#7
Re: constructor() : variable() {} <- what does it do?
What performace penalties? Can you give me link which exploits this?
You would also say that using 10+25, is less better approach than using 35?
Well, this does not make any difference. This is probably the lowest level of optimization (at code level itself) made by compiler. just as compiler would replace "10+25" with constant 35, the two types of initialization will be same.
-
October 2nd, 2005, 08:53 AM
#8
Re: constructor() : variable() {} <- what does it do?
It makes a noticeable difference:
Code:
#include <vector>
#include <iostream>
#include <windows.h>
class Test
{
public:
std::vector<int> v;
Test(const std::vector<int> &v0)//:v(v0)
{
v=v0;
}
};
int main()
{
SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS);
DWORD t0,t1;
t0=timeGetTime();
std::vector<int> v0(42);
for(std::size_t i=0;i<1000000;++i)
{
Test t(v0);
}
t1=timeGetTime();
std::cout<<"Time : "<<(t1-t0)<< " milliseconds";
return 0;
}
With "g++ -O3 -mcpu=k6-2", time is: 3430 milliseconds (+/- 1 millisecond).
With "bcc32 -O2", time is : 2322 (+/- 4 milliseconds)
Code:
#include <vector>
#include <iostream>
#include <windows.h>
class Test
{
public:
std::vector<int> v;
Test(const std::vector<int> &v0):v(v0)
{
}
};
int main()
{
SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS);
DWORD t0,t1;
t0=timeGetTime();
std::vector<int> v0(42);
for(std::size_t i=0;i<1000000;++i)
{
Test t(v0);
}
t1=timeGetTime();
std::cout<<"Time : "<<(t1-t0)<< " milliseconds";
return 0;
}
With "g++ -O3 -mcpu=k6-2", time is: 3340 milliseconds
With "bcc32 -O2", time is : 1953 milliseconds
In the first case, there is one useless default-construction.
Moreover, assignment operator is probably a bit slower than copy construction, because it tries to free the allocated memory (the difference is probably equivalent to the destruction of a default-constructed object).
My computer is a k6-2 333Mhz, with 192MB SD-RAM running at 95Mhz.
Replacing the default-construction/assignment by a copy-construction is probably forbidden by the ISO standard. And even if a compiler may do that optimization, GCC and BC++ (5.5.1) don't do it, so you should not rely on this optimization!
Instead the replacement of 10+25 by 35 is nearly imposed by the standard, because the standard introduces the notion of constant expression (what can be put between the square brackets of an array type declaration), so, since the compiler must be able to detect such constant expressions, this optimization is very natural.
"inherit to be reused by code that uses the base class, not to reuse base class code", Sutter and Alexandrescu, C++ Coding Standards.
Club of lovers of the C++ typecasts cute syntax: Only recorded member.
Out of memory happens! Handle it properly!
Say no to g_new()!
-
October 2nd, 2005, 09:16 AM
#9
Re: constructor() : variable() {} <- what does it do?
 Originally Posted by sunnypalsingh
I got this from this forum itself
Courtesy - Andreas Masur .
 Originally Posted by Rabelo
Actually it does make difference. The second case, using initialization list has better performance im most of the cases. On the 1st case the = operator is called, and on the 2nd it is not called.
Did you read whole of the post? These things are clearly mentioned there. Regards.
Can you help me with my homework assignment?, Before you post!, Use code tags, How to post!, Codeguru technical FAQs, C++ FAQ Lite, Stroustrup: C++ Style and Technique FAQ, Guru of the Week, Comeau C and C++ FAQs, Comeau C++ Templates FAQs, CUJ @ DDJ, Spam threshold
My Blogs : Learning C++ is fun | Abnegator's reflections
Open Threads : C++ Aha! Moments | Nature of work in C++?
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|