473,406 Members | 2,849 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,406 software developers and data experts.

Which causes more code-bloat: inline virtual or template class?

Greetings!!

I introduced the so-called "thin-template" pattern for controlling the
code bloat caused due to template usage.

However, one of the functions in the template happens to be virtual as
well. To support thin-template, I need to make virtual function as
inline.

Now, I know that compiler would generate an out-of-line copy when it
takes the address of my inline virtual fucntion, thus making _two_
copies of this function : one out-of-line to be used by VTABLE, and one
inline for genuine inline substituions.

Doubts:

1. Is declaring a virtual function as inline a good design? Does it
indicate their is some flaw in my design? I have not seen much code
that makes a virtual function as inline too, and hence this doubt.

2. As a rule of thumb, who should cause more code bloat : normal
template or out-of-line function? I wanna know this /cuz if template
cuase more code bloat, I wanna keep my virtual as inline. ELse I remove
thin template and make my virtual as non-inline.
The below code should give some idea as to what I am doing:

class Base
{
public:
virtual int DoSomething() = 0;
protected:
Base();
};

class IntermediateBase : public Base
{
protected:
IntermediateBase(void* aSomeParam, void* aArg) :
iSomeParam(aSomeParam), iArgs(aArg) {}
virtual int DoSomething() = 0;
protected:
void* iSomeParam;
void* iArgs;
};
template <class TYPE, class INPUT>
class ConcreteClass : public IntermediateBase
{
typedef int (TYPE::*MemberFuncPtr)(const INPUT&);
public:
inline ConcreteClass(TYPE& aCommandType, INPUT& aArgumentsToCommand,
MemberFuncPtr aMFP)
: IntermediateBase( static_cast<TYPE*>(&aCommandType),
static_cast<INPUT*>(&aArgumentsToCommand) ),
iMFP(aMFP)
{
}

inline virtual int DoSomething() // VIRTUAL AND LINE - THIS CODE
SMELLS ROT?
{
return ( static_cast<TYPE*>(iSomeParam)->*ConcreteClass::iMFP )(
*(static_cast<INPUT*>(iArgs)) );
}
private:
MemberFuncPtr iMFP;
};

Aug 25 '05 #1
6 3963
RainBow wrote:
I introduced the so-called "thin-template" pattern for controlling the
code bloat caused due to template usage.
Could you maybe share your findings how much bloat you manage to control
and what problems eliminating the bloat helps to avoid? Thanks!
[..]


V
Aug 25 '05 #2
Please note: when I say "I introduced" - I did not mean I invented
it/discovered it. I learnt this pattern when working on Symbian. If you
google for "thin template", one of the first 5 search results should
take you to Symbian site.

Also, I am sorry, but I am _not_ doing this r&d currently - I just want
a tentative answer for this. I know that the answer depends how often
are you calling the Execute() call from what all compilation units -
and I forgot to mention that in my earlier question - its just that
this inline function will be called from atmost 2 or 3 compilation
units. So is the case with template instantiation (okay, its
obvious...). :-)

I will surely post my results in this group as and when I do that
activity - but right now, I just want a rough, tentative answer so that
I can finalise my design and proceed.

Thanks,
-Viren

Aug 25 '05 #3
RainBow wrote:
I introduced the so-called "thin-template" pattern
for controlling the code bloat caused due to template usage.

However,
one of the functions in the template happens to be virtual as well.
To support thin-template, I need to make virtual function as inline.

Now, I know that compiler would generate an out-of-line copy
when it takes the address of my inline virtual fucntion,
thus making _two_ copies of this function:
one out-of-line to be used by VTABLE and
one inline for genuine inline substituions.

Doubts:

1. Is declaring a virtual function as inline a good design?
Yes.
Does it indicate [that there] is some flaw in my design?
I have not seen much code that makes a virtual function as inline too
and hence this doubt.
This is improbable.
If you apply a virtual function to an object
in the scope where it was created,
the compiler knows the actual type of the object
and a good optimizing compiler will inline the virtual function.
2. As a rule of thumb, who should cause more code bloat:
normal template or out-of-line function?
I wanna know this because, if template cuase more code bloat,
I wanna keep my virtual as inline. Otherwise,
I remove thin template and make my virtual as non-inline.

The below code should give some idea as to what I am doing:

class Base {
protected:
Base(void);
public:
virtual int DoSomething(void) = 0;
};

class IntermediateBase: public Base {
protected:
void* iSomeParam;
void* iArgs;
IntermediateBase(void* aSomeParam, void* aArg):
iSomeParam(aSomeParam), iArgs(aArg) { }
virtual
int DoSomething(void) = 0;
};

template <class TYPE, class INPUT>
class ConcreteClass: public IntermediateBase {
private:
typedef int (TYPE::*MemberFuncPtr)(const INPUT&);
MemberFuncPtr iMFP;
public:
ConcreteClass(TYPE& aCommandType,
INPUT& aArgumentsToCommand, MemberFuncPtr aMFP):
IntermediateBase(static_cast<TYPE*>(&aCommandType) ,
static_cast<INPUT*>(&aArgumentsToCommand)), iMFP(aMFP) { }

virtual
int DoSomething(void) { // VIRTUAL AND LINE - THIS CODE SMELLS ROT?
return (static_cast<TYPE*>(iSomeParam)->*ConcreteClass::iMFP)
(*(static_cast<INPUT*>(iArgs)));
}
};
inline functions do *not* cause code bloat.
They exist simply
to discourage programmers who are concerned about performance
from inlining code manually.

I *always* define inline functions (and operators)
and I let the optimizing compiler decide
whether to actually inline them or not.

inline functions can increase compile time substantially.
You might consider taking advantage of both
inline *and* external function definitions:
cat file.h #ifndef GUARD_FILE_H
#define GUARD_FILE_H 1

#ifdef EFINE_INLINE
inline
double f(double x) {
return x*(x + 2.0) + 1.0;
}
#else //EFINE_INLINE
double f(double x);
#endif//EFINE_INLINE
#endif//GUARD_FILE_H
cat file.cc #undef EFINE_INLINE
#include "file.h"

double f(double x) {
return x*(x + 2.0) + 1.0;
}
g++ -DEFINE_INLINE -Wall -ansi -pedantic -O3 -c file.cc
nm --demangle file.o

00000000 T f(double)

This allows your inline and external function definitions
to coexist peacefully.
Use the -DEFINE_INLINE option only after you have finished
testing and debugging all of your code.
This will speed up the program development cycle
and allow you to optimize your code just before deployment.
Aug 25 '05 #4
RainBow wrote:
Greetings!!

I introduced the so-called "thin-template" pattern for controlling the
code bloat caused due to template usage.

However, one of the functions in the template happens to be virtual as
well. To support thin-template, I need to make virtual function as
inline.

Now, I know that compiler would generate an out-of-line copy when it
takes the address of my inline virtual fucntion, thus making _two_
copies of this function : one out-of-line to be used by VTABLE, and one
inline for genuine inline substituions.

Doubts:

1. Is declaring a virtual function as inline a good design? Does it
indicate their is some flaw in my design? I have not seen much code
that makes a virtual function as inline too, and hence this doubt.
I wouldn't say that declaring a function inline is part of a "design"
really - I suppose it could be called a "practice". And one that is
unlikely to make much of a difference to a virtual class method. To
inline a virtual function call, the exact type of the object involved
in the call must be unvarying and be known at compile time. Needless to
say, there are few occasions where a polymorphic reference can be only
one type, and the compiler can tell what its type must be. After all,
the whole point of polymorphism is that an object's type is determined
at runtime, based on the operating state of the program.
2. As a rule of thumb, who should cause more code bloat : normal
template or out-of-line function? I wanna know this /cuz if template
cuase more code bloat, I wanna keep my virtual as inline. ELse I remove
thin template and make my virtual as non-inline.
The below code should give some idea as to what I am doing:

class Base
{
public:
virtual int DoSomething() = 0;
protected:
Base();
};

class IntermediateBase : public Base
{
protected:
IntermediateBase(void* aSomeParam, void* aArg) :
iSomeParam(aSomeParam), iArgs(aArg) {}
virtual int DoSomething() = 0;
protected:
void* iSomeParam;
void* iArgs;
};
template <class TYPE, class INPUT>
class ConcreteClass : public IntermediateBase
{
typedef int (TYPE::*MemberFuncPtr)(const INPUT&);
public:
inline ConcreteClass(TYPE& aCommandType, INPUT& aArgumentsToCommand,
MemberFuncPtr aMFP)
: IntermediateBase( static_cast<TYPE*>(&aCommandType),
static_cast<INPUT*>(&aArgumentsToCommand) ),
iMFP(aMFP)
{
}

inline virtual int DoSomething() // VIRTUAL AND LINE - THIS CODE
SMELLS ROT?
{
return ( static_cast<TYPE*>(iSomeParam)->*ConcreteClass::iMFP )(
*(static_cast<INPUT*>(iArgs)) );
}
private:
MemberFuncPtr iMFP;
};


Template code "bloat" is measured not by the total amount of code
generated from instantiating templates (which can be considerable) but
rather by the amount of duplicated code from instantiating templates
with interchangeable types (from the template's perspective). For
instance if a class template accepts a pointer type as its type
parameter, but does nothing special depending on the type being pointed
to, then instantiating the template with a series of different pointer
types will "bloat" the program with essentially duplicated code. Some
compilers can detect duplicated code and "fold" the code into a single
set of instructions (leaving stubs for the "folded" routines since
template functions must each retain a unique address). Of course if the
compiler folds duplicate code then there is less incentive for the
programmer to avoid template bloat at the source code level.

In the code above, there seems to be little opportunity for template
bloat, since the class template seems quite type-specific. Furthermore
any optimization seems premature at this point, particularly if it
complicates the implementation.

I would instead write the program using the best design available and
then test the program first for correctness, and then for performance.
If performance (measured by the speed or the size of the program) turns
out to be inadequate at that point, then it is a good idea to start
looking for optimizations. The advantage of this approach is in that
case that the program turns out to be small and fast enough using the
optimal design, then no time would have been wasted making unneeded
optimizations that would have comprised the design. And in the case
that the program turns out not to b small or fast enough, then any
optimizations that are made start with a working program - meaning that
any bugs caused by subsequent changes will be much easier to track
down.

Greg

Aug 25 '05 #5
Thank you very much Greg for that beautiful information. Surely, I am
thinking about optimisation even before a single line of code is
written - while we are still in the design phase. I think I have been
too much scared of code size (at binary level of course) of a C++
program versus a C program. In the past, I was criticised for writing
too many classes when perhaps a few C functions would have done the
trick - keeping the program size extremely small (albeit at the cost of
increasing the maintenance efforts).

This time, I did not want to take any chances and be careful about the
estiamted program size right from beginning and hence these (silly??)
concerns. :-) But your posting has opened my eyes and I realise what a
bad approach I had been taking.

Thank you very much again.

Have a great day ahead!!

--V

Aug 25 '05 #6

RainBow wrote:
Thank you very much Greg for that beautiful information. Surely, I am
thinking about optimisation even before a single line of code is
written - while we are still in the design phase. I think I have been
too much scared of code size (at binary level of course) of a C++
program versus a C program. In the past, I was criticised for writing
too many classes when perhaps a few C functions would have done the
trick - keeping the program size extremely small (albeit at the cost of
increasing the maintenance efforts).

This time, I did not want to take any chances and be careful about the
estiamted program size right from beginning and hence these (silly??)
concerns. :-) But your posting has opened my eyes and I realise what a
bad approach I had been taking.

Thank you very much again.

Have a great day ahead!!

--V


Presumably you could have the linker generate a link map for the
program you want to make smaller. A link map would tell you how how
many functions were compiled into the binary and the size of each one.
Then you would only have to work to make the functions either smaller
or fewer or both.

I think that would be a more effective approach than asking the readers
of this newgroup which functions in your program to target.

Greg

Aug 25 '05 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

10
by: Jupiter49 | last post by:
I'm trying to move pictures around on the screen, with a slight delay between the first picture and second picture (following onmousemove). When I add the setTimeout function I must be doing it...
6
by: nick | last post by:
i haven't learnt c++ before ,if i want to learn vc++,do i need to buy a c++ book to learn before i learn vc++? or some vc++ books are suitable to someone who hasn't learnt c++ before? any...
1
by: craigkenisston | last post by:
Microsoft's datarepeater sample causes warning in the IDE. Hi, The code here : ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.1033/cpgenref/html/cpconrepeaterwebservercontrol.htm Causes the...
12
by: wizard04 | last post by:
I have a drop-down list, populated from a database, a few text boxes, and a few buttons on a page. The ddl is set to autopostback. For some reason, whenever a postback happens (when an item in...
11
by: tinman | last post by:
Hi... I have the following two excerpts from a method. It basically reads data from a DataReader and loads it in a collection. Excerpt A: ******** With ProjectData
31
by: Spiro Trikaliotis | last post by:
Hello, I have a question regarding subtracting a pointer from another one. Assume I have two pointers p1 and p2, which both point to a memory area obtained with malloc(). Assume p1 = p2 + some...
15
by: Rob Meade | last post by:
Hi all, I have a databse which I'm pulling the data from for my ASP page. I have 4 tables, Course, Feature, Objective, and PreRequisite. The last three all contain a course product code and a...
7
by: semut | last post by:
Given that the string is of null-terminated type. What could be the possible causes (by experience) the string to have no null character (\0) and cause buffer overflow later. I know it is quite...
10
by: jimmy | last post by:
Hi again, sorry for posting two questions so close together but im working on a school project which is due in soon and running into some difficulties implementing the database parts. I have the...
15
by: tom | last post by:
why delete the dynamically allocated memory twice causes an error, see the code below: int _tmain(int argc, _TCHAR* argv) { int *pi = new int(12); cout<<*pi; delete pi; delete pi; }
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.