Hi I'm writing my first big object orientated program in C++ and I did it like this.
I have 3 classes TestMass, Galaxy and Universe each with a .cpp file and a .hh file. I have a make file that creates a universe.exe and in the process makes the 3 .o files. There are no implementations in the .hh file just class declarations and all member functions are defined outside of the definition in the .cpp files.
and it all works great...
Now I was told that my code has bits / all that are suitable for inlining. I've tried to work out roughly what this means but what I really want is to do it and see if my speed increases. But I'm getting confused...
To inline all my member functions of my classes do I have to get rid of the .cpp files and put everything in the .hh file? or can I just use the inline command next to my member functions in the .cpp file? How would I inline just some of my functions? What about the .o files ? If it's all inlined do theses still exist?
Sorry, im quite confused but I'm more interested in the syntax more than what's going on at a low level.
1. Move the method definition into the class definition. For example:
1 2 3 4
// header file
class A {
void f() { /*...*/ } // implicitly considered inline
};
2. Use the inline keyword and move the implementation into the header file outside of the class definition. For example:
1 2 3 4 5 6
// header file
class A {
void f();
};
inlinevoid A::f() { /*...*/ }
In either case, the definition must be in the header file to be a candidate for inlining (which is ultimately left up to the compiler). See the inclusion model and the one definition rule for more details.
EDIT: I think the best practice is to use the inline keyword at the definition not the declaration. I'm pretty sure you could use the keyword in either or even both places.
> To inline all my member functions of my classes do I have to get rid of the .cpp files and put everything in the .hh file?
You still need the .cpp file. But the definition has to be moved from the .cpp file to the header file.
You can either put them right into the class definition or put them below the class definition and add an "inline" before the method declaration in the class definition.
> How would I inline just some of my functions?
Simply just move those you want to inline and leave the others in the cpp file.
// in the header
class MyClass
{
public:
void f() {}; // implicitly inlined since definition inside class
void g(); // explicitly inlined trough keyword "inline" in the definition; definition needs to be in header
void h(); // not inlined
};
inlinevoid MyClass::g() // move this from your cpp file to the header
{
}
// in the cpp file
void MyClass::h() // leave it in the cpp file
{
}
Btw: It's finally up to the compiler what is inlined. See the "inline" keyword rather as a request or hint than a command!
It's also worth mentioning that good candidates for inlining should always be very small. If the method does time consuming work or calls other non-inlined methods, it is unlikely that removing the overhead of a relatively fast function call will be beneficial.
Inlining is not only removing the cost of the call. It is very often a step that allows more aggressive optimisations later - e.g. constructor elision, common subexpression elimination, dead code elimination etc.
So if I move a function to the header file and inline it do I completely remove its implementation in the .cpp file?
I.e. in Onur's example:
does the .cpp not mention g() at all?
also I've been taugt to put a class declaration at the top of my .cpp file as well as in the header. This seems to work so My .cpp file would be like
1 2 3 4 5 6 7 8 9 10 11 12
class MyClass
{
public:
void f() {}; // implicitly inlined since definition inside class
void g(); // explicitly inlined trough keyword "inline" in the definition; definition needs to be in header
void h(); // not inlined
};
void MyClass::h() // leave it in the cpp file
{
}
is that right?
So I should mainly be inlining my get and set member functions and some other small ones?
#include "MyClass.h"
class MyClass
{
public:
void f() {}; // implicitly inlined since definition inside class
void g(); // explicitly inlined through keyword "inline" in the definition; definition needs to be in header
void h(); // not inlined
};
void MyClass::h() // leave it in the cpp file
{
}
You cannot redefine the class. It's already defined in the header, so simply include the header.
(Don't forget the include gaurds in the header file!)
also I've been taugt to put a class declaration at the top of my .cpp file as well as in the header. This seems to work so My .cpp file would be like
Don't do that; use the include directive. Think of #include's as inserting a text file verbatum by the preprocessor. (The end result is that it is in both places.)
ok! It's almost working but I'm getting a strange error I don't understand. (firstly I removed all my redefinitions of the classes in the .cpp file and used #includes.
I then moved my simple method set Position to the testMass.hh file and removed it from the .cpp file
1 2 3 4
inlinevoid CTestMass::setPosition(const Vec2& newPosition)
{
position = newPosition;
}
and it worked (and actually ran quite a bit faster with just that small change
.
Then I tried to move another heavily used small method get Position
g++ -O2 -g -pedantic -Wall -I/ux/physics/part_2/c++ -I/usr/include/ -I/usr/include -c -o testMass.o testMass.cpp
g++ -O2 -g -pedantic -Wall -I/ux/physics/part_2/c++ -I/usr/include/ -I/usr/include -o universeClass.exe universeClass.o galaxy.o testMass.o /ux/physics/part_2/c++/cavlib/cavlib.a -lgsl -lgslcblas -lfftw3
universeClass.o: In function `circularMotionPosition(CGalaxy&, double, double)':
/home/th347/ETP/Computing/project/code/universeClass.cpp:534: undefined reference to `CTestMass::getPosition()'
universeClass.o: In function `CUniverse::initialiseSimulation_Statistics()':
/home/th347/ETP/Computing/project/code/universeClass.cpp:367: undefined reference to `CTestMass::getPosition()'
/home/th347/ETP/Computing/project/code/universeClass.cpp:367: undefined reference to `CTestMass::getPosition()'
/home/th347/ETP/Computing/project/code/universeClass.cpp:368: undefined reference to `CTestMass::getPosition()'
/home/th347/ETP/Computing/project/code/universeClass.cpp:368: undefined reference to `CTestMass::getPosition()'
universeClass.o:/home/th347/ETP/Computing/project/code/universeClass.cpp:414: more undefined references to `CTestMass::getPosition()' follow
collect2: ld returned 1 exit status
make: *** [universeClass.exe] Error 1
It doesn't seem to able to see the function CTestMass::getPosition() when its inlined in the header file although it finds it fine when it's in the .cpp file. SetPosition() is never called directly in universeClass.cpp perhaps that has something to do with it?
It seems to give this error for all my get functions but not my set functions... Is there some syntax I'm missing? The relative bit of my make file is
Just a short comment on inlining: The inline keyword is just a suggestion to the compiler. Functions that are declared as inline may be compiled as normal functions, and normal functions may be compiled as inline functions - the compiler decides on the optimizations.
and it worked (and actually ran quite a bit faster with just that small change
I can't imagine that inlining a single setter method with no logic behind it would make any real difference on runtime. Chances are your compiler inlined that function either way.
I don't think the compiler can inline functions that aren't declared as inline. At least not across different cpp files. Or if it somehow does, it doesn't optimize the same way it would if the functions were inlined.
If you think about it... I mean the compiler optimizes the code and decides whether to inline stuff. But the compiler only works on one file at a time. It can't inline a function defined in b.cpp when it's compiling a.cpp.
It isn't until linktime when the object files are tied together, and by then it's too late to modify/optimize the compiled code (other than removing bits that are unused).
I'm not 100% sure, of course, so I might be wrong. But it just seems really unlikely to me.
by "quite a bit faster" I meant a 0.2 second improvement on a 7 second run time. It's a function that gets called 10,000s of times.
Does anyone have any idea what might be causing my error above? I want to try and inline all suitable functions and try and get an overall runtime improvement.
I don't think the compiler can inline functions that aren't declared as inline. At least not across different cpp files. Or if it somehow does, it doesn't optimize the same way it would if the functions were inlined.
If you think about it... I mean the compiler optimizes the code and decides whether to inline stuff. But the compiler only works on one file at a time. It can't inline a function defined in b.cpp when it's compiling a.cpp.
It isn't until linktime when the object files are tied together, and by then it's too late to modify/optimize the compiled code (other than removing bits that are unused).
I'm not 100% sure, of course, so I might be wrong. But it just seems really unlikely to me.
This is exactly how I picture it, as well. I think it's safe to assume because, for example, g++ can be called from the command line separately for each of the objects and later linked--the compiler would have no way to know they are related calls.
It also explains why inline functions are defined in header files.
Does anyone have any idea what might be causing my error above? I want to try and inline all suitable functions and try and get an overall runtime improvement.
Post the code you have now verbatim so we can take a good look at it.
Ok (its working) inlining improved a 4.4 second time to a 4.2 second time.
Now the situation is that in some of my .cpp files there is almost no code which seems a bit silly. So I though I might as well put it all in the .hh file.
Firstly is that ok?/a good idea? / good style?
Secondly:
it didn't work
I got this error
make universeClass.exe
g++ -O2 -g -pedantic -Wall -I/ux/physics/part_2/c++ -I/usr/include/ -I/usr/include -c -o universeClass.o universeClass.cpp
make: *** No rule to make target `galaxy.o', needed by `universeClass.exe'. Stop.
which is definitely because of something in my make file. Unfortunately I really don't know a lot about make files (some one helped me write it). What do I need to change?
The make file is saying, "How do I make galaxy.o? I see that universeClass.exe wants to link with it."
From the makefile, it looks like you need a galaxy.cc or galaxy.cpp. Is galaxy just a header now? If so, remove galaxy.o from lines 17, 20, and 23; and make galaxy.o galaxy.hpp (or whatever) on lines 16, 19, and 22.