QM Bites – Order Your Includes (Twice Over)

Header includes can be a shambles. Matthew Wilson encourages us to bring some order to the chaos.
TL;DR
Order includes in groups of descending specificity and lexicographically within groups

Bite
Consider the following example of #includes in source file Cutter.cpp, containing the implementation of a class Cutter for a fictional organisation AcmeSoftware with a product Blade. In this case, the class’s implementation and header files are located in the same source directory; this need not always be so, but the discussion to follow still applies.

  #include "stdafx.h"
  #include <vector>
  #include <string>
  #include <acmecmn/string_util2.h>
  #include <acmecmn/string_util1.h>
  #include <Blade/Sharpener.hpp>
  #include <Blade/Protector.hpp>
  #include "Cutter.hpp"
  #include <stdlib.h>
  #include <map>

This is quite wrong. Here’s the right way to do it:

  #include "stdafx.h"

  #include "Cutter.hpp"

  #include <Blade/Protector.hpp>
  #include <Blade/Sharpener.hpp>

  #include <acmecmn/string_util1.h>
  #include <acmecmn/string_util2.h>

  #include <map>
  #include <string>
  #include <vector>

  #include <stdlib.h>

This has been ordered according to descending order of specificity of groups, and then lexicographically within groups. The drivers are, respectively, modularity and transparency.

The reason for descending order of specificity of groups is to expose hidden dependencies – coupling! – in any of the header files. Unlike languages such as Java and C#, the order of ‘imports’, in the form of #includes, has significance in C and C++. For example, if Cutter.hpp makes use of std::vector but does not itself include that file then compilation units that include it are at risk of compile error; the original order masks that. The same rationale applies to the files in other groups: if Blade/Sharpener.hpp requires a definition in acmecmn/string_util1.h then this would also be exposed.

The reason for lexicographical ordering with groups is to make it easier to comprehend each group’s contents. In the real world there can be many tens of included files, and if not in some readily comprehensible order then duplicates can more easily occur, which is then obviously a problem when trying to remove unnecessary includes. (Admittedly, by having a strict lexicographical ordering within groups there is a slightly increased possibility of hiding interheader coupling between files in a group, but unless you want to go to some extreme such as reverse lexicographical ordering for headers and forward for implementation files – which I do not advise – you’ll have to wear this slight risk. The grouping will take care of the vast majority.)

The reason for a blank line between groups is obvious: to delineate one group from another to further aid transparency.

 Usually, the most specific group – the Level-1 group in an implementation file – would be its declaring header(s), containing declarations of its API functions and/or defining its class: in this case Cutter.hpp. Note that it makes no difference whether the declaring header is in the same directory, i.e. #include "Cutter.hpp", or in another directory, e.g. #include <AcmeSoft/Blade/Cutter.hpp>: its pre-eminence is unchanged.

Sometimes, for implementation reasons, we have to have a Level-0 group – in this case this is the precompiled header include file stdafx.h. (In a soontobecooked Bite I will discuss why and how you should get rid of the presence of these things from your source.)

Similarly, for very rare implementation reasons, we have to have a Level-N group. I have not shown such in this case, but if you’ve chomped on enough C++ in your time you’ll have experienced such things, perhaps to conduct some shameful but necessary preprocessor surgery after all includes but before any implementation code is translated.

Hence, the rule is to order includes:

**
Order all files in groups of descending order of specificity, with each group separated by a blank line, including:
Explicit Level-0 includes (if required);
Level-1 include(s): the declaring header(s) file (for implementation files only);
Other include groups for the given application component;
Other include groups for the organisation;
Other include groups for 3rdpartysoftware;
Standard C++ headers;
Standard C headers;
Explicit Level-N includes (if required).
**

Lexicographically order all includes within groups;

Further Reading
C++ Coding Standards, Herb Sutter & Andrei Alexandrescu, AddisonWesley, 2004

Large Scale C++ Software Design, John Lakos, AddisonWesley, 1996

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值