C ++ hierarchy without source

I am developing a fairly large C ++ support library and found myself moving to a headers only approach. In C ++ it almost works because you can implement what you define in classes. For templated methods, the implementation must be in the same file anyway, so I find it much easier to just keep the implementation with the definition.

However, there are several times when you need to use "sources". As one example, sometimes circular dependencies are encountered and the implementation must be written outside of the class definition. This is how I handle it:

//part of libfoo.h
class Bar
{
  void CircularDependency(void);
};

#ifdef LIBFOO_COMPILE_INLINE
void Bar::CircularDependency(void)
{
  //...
}
#endif

      

Then the project that uses libfoo will execute the following in main.cpp:

//main.cpp
#define LIBFOO_COMPILE_INLINE
#include "libfoo.h"

      

And in any other .cpp:

//other.cpp
#include "libfoo.h"

      

The point is that the compile-inline section is only compiled once (in main.cpp).

And finally my question is, is there a name for this idiom or any other projects that work this way? This appears to be a natural result of the implementation and definition, which are blurred by the class templates and methods. And: are there any reasons why this is a bad idea or why it could potentially not scale well?

Quickly aside: I know a lot of coders, for good reason, prefer their headers to resemble interfaces rather than implementations, but doc generators are IMHO better for describing interfaces because I like to hide private members together :-)

+3


source to share


3 answers


You should use the keyword inline

if the circular dependency issue is resolved by the time you define the definition Bar::CircularDependency()

in the title libfoo.h

:

//part of libfoo.h
class Bar
{
  void CircularDependency(void);
};


// other stuff that 'resolves' the circular dependency
// ...
// ...

inline void Bar::CircularDependency(void)
{
  //...
}

      



This would make your library easier to use (the user wouldn't have to deal with what LIBFOO_COMPILE_INLINE

needed to be defined exactly in one place where the header is included).

+4


source


Circular dependencies are not really a problem as you can forward the decal to have the functions inline. I wouldn't suggest it, though: while the "original" approach initially makes it easier to use a library that comes from somewhere, it results in longer compilation times and tighter communication between files. In a huge source base, this essentially kills the hOpe to get the code assembled in a reasonable amount of time. Of course, a huge one only starts with a couple of million lines of code, but who is interested in trivial programs ...? (and, yes, the place I work in contains tens of millions of lines of code that are built into single executables)



+2


source


My reasons why this is a bad idea.

Increased compilation time

Every single compilation unit that includes a header must compile all header files in addition to the source itself. This will likely increase compile times and can be frustrating when testing your code with minor changes. One could argue that the compiler can optimize it, but IMO cannot optimize it beyond the point.

Higher code segment

If all functions are written inline, it means that the compiler has to put all this code wherever the function is called. This will cause the code segment to explode, and it will affect the load time of the program and the program will take up more memory.

Creates a dependency in tightly coupled client code

Whenever you change your implementation, each client must be updated (by recompiling the code). But if the implementation has been placed in an independent shared object (.so or .dll), the client should simply refer to the new shared object.

Also I don't know why this can be done.

//main.cpp
#define LIBFOO_COMPILE_INLINE
#include "libfoo.h"

      

If it needs to be done at all, he could just put the implementation code in main.cpp. In any case, you can define LIBFOO_COMPILE_INLINE in only one compilation block. Otherwise, you will duplicate definitions.

I am really very interested in developing an idiom for writing cohesive template code. Sometime in the future, the C ++ compiler should support creating cohesive patterns. By this I mean that the client does not need to recompile the code whenever the implementation of the template changes.

+2


source







All Articles