Item 26. Minimizing Compile-time Dependencies part 1

I l@ve RuBoardPrevious Section Next Section

Item 26. Minimizing Compile-time Dependencies桺art 1

Difficulty: 4

When we talk about dependencies, we usually think of run-time dependencies like class interactions. In this Item, we will focus instead on how to analyze and manage compile-time dependencies. As a first step, try to identify (and root out) unnecessary headers.

Many programmers habitually #include many more headers than necessary. Unfortunately, doing so can seriously degrade build times, especially when a popular header file includes too many other headers.

In the following header file, which #include directives could be immediately removed without ill effect? You may not make any changes other than removing or rewriting #include directives. Note that the comments are important.

//  x.h: original header 
//
#include <iostream>
#include <ostream>
#include <list>
// None of A, B, C, D or E are templates.
// Only A and C have virtual functions.
#include "a.h"  // class A
#include "b.h"  // class B
#include "c.h"  // class C
#include "d.h"  // class D
#include "e.h"  // class E
class X : public A, private B
{
public:
     X( const C& );
  B  f( int, char* );
  C  f( int, C );
  C& g( B );
  E  h( E );
  virtual std::ostream& print( std::ostream& ) const;
private:
  std::list<C> clist_;
  D            d_;
};
inline std::ostream& operator<<( std::ostream& os, const X& x )
{
  return x.print(os);
}
  •  
 
I l@ve RuBoardPrevious Section Next Section
 
I l@ve RuBoardPrevious Section Next Section

Solution

graphics/bulb_icon.gif

Of the first two standard headers mentioned in x.h, one can be immediately removed because it's not needed at all, and the second can be replaced with a smaller header.

  1. Remove iostream.

    #include <iostream> 
    

    Many programmers #include <iostream> purely out of habit as soon as they see anything resembling a stream nearby. X does make use of streams, that's true; but it doesn't mention anything specifically from iostream. At the most, X needs ostream alone, and even that can be whittled down.

    Guideline

    graphics/guideline_icon.gif

    Never #include unnecessary header files.


  2. Replace ostream with iosfwd.

    #include <ostream> 
    

    Parameter and return types need only to be forward-declared, so instead of the full definition of ostream we really only need its forward declaration.

In the old days, you could just replace "#include <ostream>" with "class ostream;" in this situation, because ostream used to be a class and it wasn't in namespace std. Alas, no more. Writing "class ostream;" is illegal for two reasons.

  1. ostream is now in namespace std, and programmers aren't allowed to declare anything that lives in namespace std.

  2. ostream is now a typedef of a template; specifically, it's typedef'd as basic_ostream<char>. Not only would the basic_ostream template be messy to forward-declare in any case, but you couldn't reliably forward-declare it at all, because library implementations are allowed to do things like add their own extra template parameters (beyond those required by the standard), which, of course, your code wouldn't know about梠ne of the primary reasons for the rule that programmers aren't allowed to write their own declarations for things in namespace std.

    All is not lost, however. The standard library helpfully provides the header iosfwd, which contains forward declarations for all the stream templates (including basic_ostream) and their standard typedefs (including ostream). So all we need to do is replace "#include <ostream>" with "#include <iosfwd>".

    Guideline.

    graphics/guideline_icon.gif

    Prefer to #include <iosfwd> when a forward declaration of a stream will suffice.


    Incidentally, once you see iosfwd, one might think that the same trick would work for other standard library templates, such as list and string. There are, however, no comparable "stringfwd" or "listfwd" standard headers. The iosfwd header was created to give streams special treatment for backward compatibility, to avoid breaking code written in years past for the "old" nontemplated version of the iostreams subsystem.

    There, that was easy. We can…

    What? "Not so fast!" I hear some of you say. "This header does a lot more with ostream than just mention it as a parameter or return type. The inlined operator<< actually uses an ostream object! So it must need ostream's definition, right?"

    That's a reasonable question. Happily, the answer is: No, it doesn't. Consider again the function in question:

    inline std::ostream& operator<<( std::ostream& os, const X& x ) 
    {
    return x.print(os);
    }
    

    This function mentions an ostream& as both a parameter and a return type (which most people know doesn't require a definition), and it passes its ostream& parameter in turn as a parameter to another function (which many people don't know doesn't require a definition either). As long as that's all we're doing with the ostream&, there's no need for a full ostream definition. Of course, we would need the full definition if we tried to call any member functions, for example, but we're not doing anything like that here.

    So, as I was saying, we can get rid of only one of the other headers just yet.

  3. Replace e.h with a forward declaration.

    #include "e.h"  // class E 
    

Class E is just being mentioned as a parameter and as a return type, so no definition is required, and x.h shouldn't be pulling in e.h in the first place. All we need to do is replace "#include "e.h"" with "class E;".

Guideline

graphics/guideline_icon.gif

Never #include a header when a forward declaration will suffice.


  •  
 
I l@ve RuBoardPrevious Section Next Section
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值