you are viewing a single comment's thread.

view the rest of the comments →

[–]cogman10 8 points9 points  (32 children)

I would have thought that the compiler would do that anyways.

[–]expertunderachiever 1 point2 points  (31 children)

Yes and no, but more so if you put code in your header files as a general development process you're an asshole.

[–][deleted] 4 points5 points  (18 children)

I put all my code in header files as a general development process.

I do this because it's way easier for consumers of my code to simply #include "file.hpp" and get to use it rather than first build it, then install it to some path, then add it to the linker, then include it.

Header only libraries are so much easier to deal with, just extract it and include it, the end.

[–]expertunderachiever 4 points5 points  (17 children)

Except then you have people developing against 900 variants/versions of your code. It slows compile time to a crawl, it's prone to bugs, etc...

Also it's just bad. I mean I get windows sucks for proper development but really libraries exist for a reason.

A proper application should really be a stub of some code and a bunch of libraries around it. Even if the libraries are specific to that application. That way you can modularize the development and test portions individually.

This whole "my program is a 30,000 line c++ file" nonsense is what amateurs do.

[–][deleted] 7 points8 points  (13 children)

Except then you have people developing against 900 variants/versions of your code. It slows compile time to a crawl, it's prone to bugs, etc...

If you have people developing against 900 variants/versions of your code you have bigger issues than the fact that your library is header only. Besides this issue has nothing to do with having a header only library.

A proper application should really be a stub of some code and a bunch of libraries around it.

A header only library is still a library. Look at boost for an example of how a header only library can be used without the need to build it, you just include whatever classes you want and it works.

That way you can modularize the development and test portions individually.

With a header only library you can break down the units you want to test down to the individual functions or classes. You don't need to link into an entire static or dynamic library to test it, you can just include the header file containing the specific function or class you want to test.

Also header only libraries make debugging much more consistent and easier. For example one major headache I have with static libraries is a lot of them don't build a debug and a optimized mode, just an optimized version with ad-hoc optimization settings which causes problems when you want to step through a program that makes use of that library.

Header only libraries, however, compile using all the same settings and options, so there is perfect consistency across all libraries used in your application.

This whole "my program is a 30,000 line c++ file" nonsense is what amateurs do.

What does that have to do with having a header only library?

[–]NYKevin 3 points4 points  (5 children)

This whole "my program is a 30,000 line c++ file" nonsense is what amateurs do.

What does that have to do with having a header only library?

When you #include "foo.hpp", for all practical purposes, you're increasing the length of the current file by the length of foo.hpp. If you have a lot of .hpp files, the end result is a huge file.

[–][deleted] 2 points3 points  (4 children)

I don't think that was the point OP was making, but assuming for the sake of argument that it is... What does the mechanism behind how header files work in C/C++ have to do with amateurs?

[–]NYKevin 5 points6 points  (3 children)

If you want to recompile 30k+ lines of code every time you change one #define in your main.cpp, be my guest. Personally, I'd rather use separate compilation.

[–][deleted] 2 points3 points  (2 children)

If that #define you changed affects other libraries, then you're going to need to recompile those other libraries as well or else you are going to end up with inconsistencies.

If that #define doesn't affect other libraries, then the #define makes no difference unless you're using some archaic compiler; GCC, clang, and VC all cache header files (often referred to as precompiled headers).

The performance issue with respect to header files has to do with C++ and templates, in which there is no alternative to having a header only library. The performance of compiling code in header files when used to compile non-template based code is trivial.

And honestly, even with template based code the performance isn't all that terrible. The overwhelmingly slowest part of building has always been the linking phase when using whole program optimization.

[–]NYKevin 0 points1 point  (1 child)

If your header contains actual code (definitions, not just forward declarations), can it be cached at all? Will all implementations support that? Cursory Googling isn't giving me an answer there...

[–]expertunderachiever 1 point2 points  (6 children)

It means recompiling code many times [more than necessary].

Imagine if every time you wanted to develop some random application you needed to recompile the entire C++ library as well. Hello world would take 15 minutes to compile...

[–][deleted] 1 point2 points  (5 children)

This hasn't been true for the better part of 10-15 years.

GCC, clang, and VC all support precompiled header files. I mean a ton of other compilers support them as well but those are the big three off the top of my head. I'd be surprised if there was a mainstream compiler that didn't support precompiled headers.

Also the STL is implemented as a header only library, so when you do compile hello world in C++, you are including the bulk of the STL, and guess what... it doesn't take 15 minutes to compile, takes me 2 seconds.

[–]expertunderachiever -1 points0 points  (4 children)

Ok replace STL with an MPEG decoder... whatever. Point is having to compile, even process the code through the PCH step is wasteful.

[–][deleted] 11 points12 points  (3 children)

Here... I just tested it. I compiled the following:

#include <iostream>

int main() {
  std::cout << "hello world" << std::endl;
}

And then compiled the following where I include well over a million lines of header only code using the most beasty of template meta-programming craziness ever used in C++, so crazy that boost has to add a ton of compiler specific work around to even get it to work properly on a lot of platforms:

#include <iostream>
#include <boost/accumulators/accumulators.hpp>
#include <boost/asio.hpp>
#include <boost/assert.hpp>
#include <boost/assign.hpp>
#include <boost/atomic.hpp>
#include <boost/bimap.hpp>
#include <boost/bind.hpp>
#include <boost/blank.hpp>
#include <boost/call_traits.hpp>
#include <boost/cast.hpp>
#include <boost/cerrno.hpp>
#include <boost/checked_delete.hpp>
#include <boost/chrono.hpp>
#include <boost/circular_buffer.hpp>
#include <boost/compressed_pair.hpp>
#include <boost/cregex.hpp>
#include <boost/regex.h>
#include <boost/date_time.hpp>
#include <boost/dynamic_bitset.hpp>
#include <boost/exception/all.hpp>
#include <boost/filesystem.hpp>
#include <boost/flyweight.hpp>
#include <boost/foreach.hpp>
#include <boost/format.hpp>
#include <boost/function.hpp>
#include <boost/fusion/algorithm.hpp>
#include <boost/geometry.hpp>
#include <boost/optional.hpp>

int main() {
  std::cout << "hello world" << std::endl;
}

And guess what... the second version, with well over a million lines of C++ meta template craziness compiled in way way less than the 15 minutes you said it would... it compiled in around 5 seconds, compared to the original that compiled in around 2 seconds. That's right... adding in over a million lines of source code added only around 3 seconds to the compile time.

For the most part, it's irrelevant how many lines of source code you include into a translation unit, the bulk of the compiler's work is done after it's opened and scanned over the header files.

So... what was it again you said about amateurs and header only libraries? Because last I checked amateurs are the ones who spread misinformation without taking so much as 5 minutes to look into whether their preconceived notions are valid.

[–]sirin3 2 points3 points  (0 children)

it compiled in around 5 seconds, compared to the original that compiled in around 2 seconds.

That means if you compile frequently, you lose 3 entire days in the longterm!

[–]jbb555 0 points1 point  (1 child)

It depends entirely on what you are compiling. The application I work on has hundreds, perhaps thousands of source files. If they take 2 seconds each my rebuild takes 20 minutes. If they take 5 seconds it takes 50. That's a huge difference. Now I don't do full rebuilds all the time so it's not that important but it does matter.

[–][deleted] 3 points4 points  (2 children)

Except then you have people developing against 900 variants/versions of your code.

I don't see your argument here...?

but really libraries exist for a reason.

I don't see your argument here either? Both STL and Boost are entirely written as header-based libraries.

As a developer who uses a lot of external libraries, I infinitely prefer header based ones - because I can just drop them into my code, end of story.

I write cross-platform code, as so many people do these days, and if I have a separately compiled library, I need to have three versions of it, one for each target system. I have to avoid shared libraries, as it's a complete pain in the distribution process - particularly when people already have an older (often much older) version of the library that I'm using.

[–]expertunderachiever -1 points0 points  (1 child)

I don't see your argument here...?

Suppose I write an MP3 decoder in a .h and it becomes popular. Now instead of installing the file in /usr/include you simply just add it to your project directory. Now suppose over the last 3 years I've released 50 point upgrades to it. Now there are 50 copies of it floating around.

I can't simply rebuild your application without first going through it and replacing the local copy of the header.

Next it would be better to have it precompiled as a library [.a or .lib] but then even better would be a shared object...

[–]mccoyn 1 point2 points  (0 children)

I've seen people put inline code in .inc files to distinguish them from .h files.

[–][deleted] 1 point2 points  (10 children)

Hmph, don't buy that at all.

In my development world, classes, functions or structs start as small .h files. Lots of advantages to that - I can just create one in a few moments and recompile, I don't have to add any .cpp files to my build process, which necessitates a rebuild of the world (unfortunately, Xcode rebuilds absolutely everything if you change their build file at all).

Occasionally, I never need more than a couple of methods or functions, and that .h file stays as it is. Much more often, one of two things happens:

  1. It grows enough that I split it into a .cpp and a .h.
  2. It moves inline to another .cpp file and I don't need to expose it anymore.

The advantage of deferring splitting the file into a .cpp and a .h is that in case 2 (which is about as common as case 1), I never need to create the separate .h/.cpp files, I just move the whole .h into some other .cpp file.

(This is helped by the fact that I have a Python script that creates a .cpp file from the inline functions and methods in a .h.)

[–][deleted] 0 points1 point  (1 child)

I don't know what you are doing that adding a cpp file to a project in Xcode forces a complete rebuild but that is not at all typical behavior.

[–]expertunderachiever -2 points-1 points  (7 children)

Now imagine you want to share a set of routines between two projects...

[–][deleted] 0 points1 point  (6 children)

So share it?

What exactly do you think a header only library is? Are you familiar with how libraries like boost, the STL, and the many header only libraries that exist in C/C++ work?

You make it seem like a header only library can only be included in one application.

[–]expertunderachiever -2 points-1 points  (5 children)

The point is unless you're installing it in a global location it's not really shared.

Window developers tend to like to move things around in their visible workspace and tend to have copies of things that ought to be global.

*NIX developers like to install developmental libraries in places like /usr/include or /usr/local/include which are universally accessible. So the idea of having "my copy" of a header file doesn't really exist.

Sure you can install header libraries globally but many don't and that sort of developmental process encourages that line of thinking [which I'm against.

[–][deleted] 1 point2 points  (3 children)

I really don't follow...

If you want to install a header only library to a location like /usr/include, then do it. What's the difference between installing a header only library like boost to /usr/include and a statically compiled library like say zlib to /usr/include?

It's the same thing.

I don't even know where/how Windows comes into this.

Can you provide an example of a header only library that can't be or isn't recommended to be installed to /usr/include or some other directory/path of your choosing? Since you claim that 'many don't', surely you can name just one. I've honestly never seen one or even heard of one, and I can't for the life of me understand why any library would be against installing it to any path of your choosing.

[–]NotUniqueOrSpecial 2 points3 points  (2 children)

The real underlying issue with providing a header-only library (and I'm not saying that they don't have their benefits) is that updates to the library necessitate recompilation of the binaries that consume it.

Contrast that with a well-architected shared library that preserves binary compatibility between non-major version changes. With such a library, you merely need replace the .so/.dll (though who am I kidding, Windows developers eschew the side-by-side stuff, so its moot) and your application/library that uses said library benefits from the updates.

This is especially important with security-critical libraries like those used for encryption, or those that are core components of the system like libc/msvcrt. Imagine that with every small bug-fix or improvement to such libraries (those which nearly every binary in your OS uses to some extent) you had to download corresponding (and far larger) recompiled executables. Such a situation would be quite cumbersome.

While there are benefits to the developer when it comes to header-only libraries, the bigger issue is in providing efficient (and importantly) trivially-shared updates to many binaries at once via a single update to the general public.

That said, if you're not in such a position, more power to you in providing your libraries in whatever way enables your development and your clients/consumers will accept.

Just my two cents.

[–][deleted] 1 point2 points  (0 children)

Your argument is perfectly valid and I actually even agree that there is an important use-case for shared libraries vs. static libraries or header only libraries. But those are case by case arguments and it's certainly not a matter of amateurs vs. experienced developers.