Sign in to follow this  
dmatter

which #include method is better....

Recommended Posts

dmatter    4821
Which method is better in terms of compile speed and .exe size:
//In my_utils.h

#include <vector>
#include <map>
#include <string>
//..etc...

//-----------------
//In my_class.h

#include "my_utils.h" //has everything even though it only needs a vector

class some_class
{
    std::vector <int> int_array;

public:
    //some member functions....
};


or...
//In my_class.h
#include <vector> //every file that needs a vector must include the file

class some_class
{
    std::vector <int> int_array;

public:
    //some member functions....
};


I've never been quite sure how the compiler puts together translation units especially ones containing templated code. Any thoughts? Thanks :)

Share this post


Link to post
Share on other sites
Skizz    794
The first method will be considerably faster to compile if you use precompiled headers correctly. The two versions should produce the same code.

Skizz

Share this post


Link to post
Share on other sites
It's a matter of coupling and what you really want is to in headers include the bare minimum to make them compile as the only line in an implementation file.

That often means forward declaring classes only passed and returned as pointers or references.

This is a good thing since it physicly decouples your project proventing a small change to erupt into a nasty recompile of the whole codebase.

Sure it will require some extra typing on your part but in the long run you'll have a much healtiher codebase from it.

Oh, and about speed, modern compilers are smart enough to not reread headers included multiple times rendering use of "hacks" like #pragma once needless to.

Share this post


Link to post
Share on other sites
ToohrVyk    1595
Quote:
Original post by DigitalDelusion
Oh, and about speed, modern compilers are smart enough to not reread headers included multiple times rendering use of "hacks" like #pragma once needless to.


Is this really a good thing? Consider the following situation:


// foo.h
#ifndef ONCE
int foo(int bar) { return bar; }
#define ONCE
#else
#ifndef TWICE
#define TWICE
int foo(float bar) { return bar * 2.0f; }
#endif
#endif

//foo.c
#include <iostream>
#include "foo.h"
#include "foo.h"

int main() {

std::cout << foo(1.0f) << std::endl;
return 0;
}



A "smart" compiler that ignores duplicate includes will display "1", a standards-respecting compiler would display "2.00000".

Share this post


Link to post
Share on other sites
Quote:
Original post by DigitalDelusion
Oh, and about speed, modern compilers are smart enough to not reread headers included multiple times rendering use of "hacks" like #pragma once needless to.


That would actually be very, very stupid of a compiler.
Try this:

//Test.h
#ifdef MYDEFINE
void DoSomething(){}
#else
void DoSomethingElse(){}
#endif
//main.h
#include "Test.h"
#define MYDEFINE
#include "Test.h"
int main()
{
DoSomething();
DoSomethingElse();
}




Notice that the two places I include will produce different code. Why would I want to do this? Check out boost::preprocessor for using this multiple including of the same file to great effect.

You can also try including a file twice in your favorite compiler and observe the errors that occur.

Edit: Seems ToohrVyk and I were thinking the same thing, I just took longer to type the message. ;)

Share this post


Link to post
Share on other sites
#pragma once is a ugly hack, proper use of inclusion guards are not.

Im fully aware that you can want diffrent things from the same file (X macros comes to mind) and maybe I should have been explicit about the compiler not reread the file.

It has been benchmarked in various sources that using "#pragma once" doesn't provide any benefit at all over using normal inclusion guards, and that there very seldom is any benefit in using external guards.

Share this post


Link to post
Share on other sites
dmatter    4821
Wow fast replies!! [smile]

So as I understand it the first method will reduce compile time whilst the second method would reduce the size of the executable?

Since the STL headers contain template code does that mean they are compiled differently - i.e. only compiled when actually used.

Share this post


Link to post
Share on other sites
Ready4Dis    180
Quote:
Original post by ToohrVyk
Quote:
Original post by DigitalDelusion
Oh, and about speed, modern compilers are smart enough to not reread headers included multiple times rendering use of "hacks" like #pragma once needless to.


Is this really a good thing? Consider the following situation:

*** Source Snippet Removed ***

A "smart" compiler that ignores duplicate includes will display "1", a standards-respecting compiler would display "2.00000".


A "smart" compiler should complain of multiple function declarations, so a standards compiler would not display 2, it wouldn't display anything but an error ;).

Share this post


Link to post
Share on other sites
Quote:
Original post by dmatter
Wow fast replies!! [smile]

So as I understand it the first method will reduce compile time whilst the second method would reduce the size of the executable?

Since the STL headers contain template code does that mean they are compiled differently - i.e. only compiled when actually used.


The linker will happily flush them out anyhow so exe size till be constant. It's the same as with unused functions even if they do end up in our object files the linker happily removes them later if they're never referenced.

Share this post


Link to post
Share on other sites
Quote:
Original post by dmatter
Wow fast replies!! [smile]

So as I understand it the first method will reduce compile time whilst the second method would reduce the size of the executable?

Since the STL headers contain template code does that mean they are compiled differently - i.e. only compiled when actually used.


Truly, the benifit to the second method, that is including only what the header file itself needs in the header and including what the source file needs in the source file, is that you can quickly yank the header and source from one project and dump it into another, without having to edit the files. It also provides faster minimal-rebuilds, because changing one header only causes recompilation of files actually affected rather than pretty much all files (proper use of precompile headers probably prevents this, I don't know, I use the minimal inclusion method primarilly for the first reason I list).

Share this post


Link to post
Share on other sites
Enigma    1410
Quote:
Original post by ToohrVyk
Quote:
Original post by DigitalDelusion
Oh, and about speed, modern compilers are smart enough to not reread headers included multiple times rendering use of "hacks" like #pragma once needless to.


Is this really a good thing? Consider the following situation:

<following situation>

A "smart" compiler that ignores duplicate includes will display "1", a standards-respecting compiler would display "2.00000".

I think I read somewhere that some compilers* actually store some form of parse tree from the header, so they can correctly handle multiple includes of the same file with different #defined tokens but still avoid re-parsing the file each time. So the difference in speed between #pragma once and inclusion guards could typically be measured in clock ticks, whereas the difference between re-reading the file for the above situation and re-processing the parse tree is much more significant.

Enigma

*I think this was an article refering to gcc. Of course that could be obsolete information, bad information or plans for a future implementation, I don't recall the article well enough to be sure.

Share this post


Link to post
Share on other sites
ToohrVyk    1595
Quote:
Original post by Ready4Dis
A "smart" compiler should complain of multiple function declarations, so a standards compiler would not display 2, it wouldn't display anything but an error ;).


In C++, declaring int foo(int bar) and float foo(float bar) is allowed (and known as function overloading). The difference in behavior relied on the fact that I was passing the function a float (with an int, both compilers would have behaved the same way), hence triggering the use of different overloads of the function if they are available.

And since the (devilish, I agree) include guards prevent the definition of each function more than once, the compiler has nothing to complain about.

You are right, however, that it would be wise to add the keyword "static" to the functions, so the linker won't throw a fit when it notices the functions being defined in several compilation units. If we were crazy enough to use this code in a project with more than one cpp file. [grin]

Share this post


Link to post
Share on other sites
Enigma    1410
Quote:
Original post by ToohrVyk
You are right, however, that it would be wise to add the keyword "static" to the functions, so the linker won't throw a fit when it notices the functions being defined in several compilation units. If we were crazy enough to use this code in a project with more than one cpp file. [grin]

It would be smarter to add them to the anonymous namespace, since the use of static in this situation is deprecated (link).

Enigma

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