Clean Up Your #Include Statements

Clean up your #include statements?

To verify that header files are including everything they need, I would creating a source file that all it does is include a header file and try to compile it. If the compile fails, then the header file itself is missing an include.

You get the same effect by making the following rule: that the first header file which foo.c or foo.cpp must include should be the correspondingly-named foo.h.
Doing this ensures that foo.h includes whatever it needs to compile.

Furthermore, Lakos' book Large-Scale C++ Software Design (for example) lists many, many techniques for moving implementation details out of a header and into the corresponding CPP file. If you take that to its extreme, using techniques like Cheshire Cat (which hides all implementation details) and Factory (which hides the existence of subclasses) then many headers would be able to stand alone without including other headers, and instead make do with just forward declaration to opaque types instead ... except perhaps for template classes.

In the end, each header file might need to include:

  • No header files for types which are data members (instead, data members are defined/hidden in the CPP file using the "cheshire cat" a.k.a. "pimpl" technique)

  • No header files for types which are parameters to or return types from methods (instead, these are predefined types like int; or, if they're user-defined types, then they're references in which case a forward-declared, opaque type declaration like merely class Foo; instead of #include "foo.h" in the header file is sufficient).

What you need then is the header file for:

  • The superclass, if this is a subclass

  • Possibly any templated types which are used as method parameters and/or return types: apparently you're supposed to be able to forward-declare template classes too, but some compiler implementations may have a problem with that (though you could also encapsulate any templates e.g. List<X> as implementation details of a user-defined type e.g. ListX).

In practice, I might make a "standard.h" which includes all the system files (e.g. STL headers, O/S-specific types and/or any #defines, etc) that are used by any/all header files in the project, and include that as the first header in every application header file (and tell the compiler to treat this "standard.h" as the 'precompiled header file').


//contents of foo.h
#ifndef INC_FOO_H //or #pragma once
#define INC_FOO_H

#include "standard.h"
class Foo
{
public: //methods
... Foo-specific methods here ...
private: //data
struct Impl;
Impl* m_impl;
};
#endif//INC_FOO_H

//contents of foo.cpp
#include "foo.h"
#include "bar.h"
Foo::Foo()
{
m_impl = new Impl();
}
struct Foo::Impl
{
Bar m_bar;
... etc ...
};
... etc ...

Detecting superfluous #includes in C/C++?

It's not automatic, but doxygen will produce dependency diagrams for #included files. You will have to go through them visually, but they can be very useful for getting a picture of what is using what.

Automatically removing unneeded #include statements

There have been lots of questions here similar to this. So far, no-one has come up with a really good tool to list the dependancy graph and hilight multiple includes etc. (favourite seems to be doxygen) much less perform edits on the files themselves. So I would guess the anser is going to be "No" - I'd be happy to be wrong, however!

Where to put include statements, header or source?

Only put includes in a header if the header itself needs them.

Examples:

  • Your function returns type size_t. Then #include <stddef.h> in the header file.
  • Your function uses strlen. Then #include <string.h> in the source file.

How should I detect unnecessary #include files in a large C++ project?

While it won't reveal unneeded include files, Visual studio has a setting /showIncludes (right click on a .cpp file, Properties->C/C++->Advanced) that will output a tree of all included files at compile time. This can help in identifying files that shouldn't need to be included.

You can also take a look at the pimpl idiom to let you get away with fewer header file dependencies to make it easier to see the cruft that you can remove.

Cleaning up Legacy Code header spaghetti

Assuming you're familiar with "include guards" (#ifdef at the begining of the header..), an additional way of speeding up build time is by using external include guards.
It was discussed in "Large Scale C++ Software Design". The idea is that classic include guards, unlike #pragma once, do not spare you the preprocessor parsing required to ignore the header from the 2nd time on (i.e. it still has to parse and look for the start and end of the include guard. With external include guards you place the #ifdef's around the #include line itself.

So it looks like this:

#ifndef MY_HEADER
#include "myheader.h"
#endif

and of course within the H file you have the classic include guard

#ifndef MY_HEADER
#define MY_HEADER

// content of header

#endif

This way the myheader.h file isn't even opened / parsed by the preprocessor, and it can save you a lot of time in large projects, especially when header files sit on shared remote locations, as they sometimes do.

again, it's all in that book. hth

entity framework core reuse a set of include statements

Try this:

public static class DataExtensions
{
public static Microsoft.EntityFrameworkCore.Query.IIncludableQueryable<Account, List<Admin>> CustomIncludes(this DbSet<Account> accounts)
{
return accounts
.Include(p => p.Status)
.Include(p => p.Type)
.Include(p => p.Phones)
.Include(p => p.Users)
.Include(p => p.Admins);
}
}

Then you can say

context.Accounts.CustomIncludes();

Cleaning up nested if statements

Is there [...] a more readable/efficient approach on my problem

Step 1. Look around for a classical example of text parser

Answer: a compiler, which parses text files and produces different kind of results.

Step 2. Read some theory how does compilers work

There are lots of approaches and techniques. Books, online and open source examples. Simple and complicated.

Sure, you might just skip this step if you are not that interested.

Step 3. Apply theory on you problem

Looking through the theory, you will no miss such therms as "state machine", "automates" etc. Here is a brief explanation on Wikipedia:

https://en.wikipedia.org/wiki/Automata-based_programming

There is basically a ready to use example on the Wiki page:

#include <stdio.h>
enum states { before, inside, after };
void step(enum states *state, int c)
{
if(c == '\n') {
putchar('\n');
*state = before;
} else
switch(*state) {
case before:
if(c != ' ') {
putchar(c);
*state = inside;
}
break;
case inside:
if(c == ' ') {
*state = after;
} else {
putchar(c);
}
break;
case after:
break;
}
}
int main(void)
{
int c;
enum states state = before;
while((c = getchar()) != EOF) {
step(&state, c);
}
if(state != before)
putchar('\n');
return 0;
}

Or a C++ example with state machine:

#include <stdio.h>
class StateMachine {
enum states { before = 0, inside = 1, after = 2 } state;
struct branch {
unsigned char new_state:2;
unsigned char should_putchar:1;
};
static struct branch the_table[3][3];
public:
StateMachine() : state(before) {}
void FeedChar(int c) {
int idx2 = (c == ' ') ? 0 : (c == '\n') ? 1 : 2;
struct branch *b = & the_table[state][idx2];
state = (enum states)(b->new_state);
if(b->should_putchar) putchar(c);
}
};
struct StateMachine::branch StateMachine::the_table[3][3] = {
/* ' ' '\n' others */
/* before */ { {before,0}, {before,1}, {inside,1} },
/* inside */ { {after, 0}, {before,1}, {inside,1} },
/* after */ { {after, 0}, {before,1}, {after, 0} }
};
int main(void)
{
int c;
StateMachine machine;
while((c = getchar()) != EOF)
machine.FeedChar(c);
return 0;
}

Sure, instead of chars you should feed lines.

This technique scales up to a complicated compilers, proven with tons of implementations. So if you are looking for a "right" approach, here it is.

Cleaning up multiple if statements C++

First off,

ISecret = rand() % 10, 1;

is wrong. This statement is equivalent to ISecret = rand() % 10; and the 1 has no effect (this should trigger a compiler warning).

If you want a random number in the range [1, 10] (inclusive), you should do:

ISecret = rand() % 10 + 1;

To select a word for a given number, the easiest way is probably an array:

const FString hidden_word[] = {
"planet",
"bait",
"dog",
"cat",
"stream",
"taco",
"ship",
"balcony",
"tail",
"barf"
};
ISecret = rand() % 10; // a number between 0 and 9
MyHiddenWord = hidden_word[ISecret];


Related Topics



Leave a reply



Submit