Google样式指南(正向分节)

时间:2018-09-17 21:47:24

标签: c++ design-guidelines

序言

《 Google风格指南》中列出了一些前向声明的缺点

  1. 转发声明可以隐藏依赖项,从而允许用户代码在标头更改时跳过必要的重新编译。

  2. 对库的后续更改可能会破坏前向声明。函数和模板的前向声明可以防止标头所有者对其API进行其他兼容的更改,例如扩展参数类型,添加具有默认值的模板参数或迁移到新的命名空间。

  3. 从命名空间std ::转发声明符号会产生未定义的行为。

  4. 很难确定是否需要前向声明或完整的#include。用前向声明替换#include可以静默更改代码的含义:

代码:

  // b.h:
  struct B {};
  struct D : B {};

  // good_user.cc:
  #include "b.h"
  void f(B*);
  void f(void*);
  void test(D* x) { f(x); }  // calls f(B*)

如果将#include替换为B和D的正向decl,则test()将调用f(void *)。

  1. 从头文件中声明多个符号比仅#include头文件更冗长。

  2. 构造代码以启用前向声明(例如,使用指针成员而不是对象成员)可以使代码更慢,更复杂。

问题

我对第一点特别感兴趣,因为我无法提出一个单一的方案,即当标头更改时,前向取消会跳过必要的重新编译。谁能告诉我这是怎么发生的?还是这是Google代码库所固有的?

由于这是列表上的第一点,因此似乎也很重要。

2 个答案:

答案 0 :(得分:2)

  

我无法提出一个单一的方案,即当标头更改时,前向声明会跳过必要的重新编译。

我认为这也不太清楚,也许措辞可能更清楚。

隐藏依赖项是什么意思?

假设您的文件main.cc需要header.h才能正确构建。

  • 如果main.cc包含header.h,则这是直接依赖项。

  • 如果main.cc包含lib.h,然后lib.h包含header.h,则这是间接依赖。

  • 如果main.cc某种程度上依赖于lib.h,但是如果不包含lib.h却没有生成构建错误,那么我可以称其为 hidden 依赖关系。

我不认为 hidden 这个字眼是常识,但是,我同意可以改进或扩展其措词。

这是怎么发生的?

我有main.clib.htypes.h

这里是main.c

#include "lib.h"
void test(D* x) { f(x); }

这里是lib.h

#include "types.h"
void f(B*);
void f(void*);

这里是types.h

struct B {};
struct D : B {};

现在,main.cc依赖于types.h来生成正确的代码。但是,main.cc仅对lib.h有直接依赖关系,对types.h hidden 依赖关系。如果我在lib.h中使用前向声明,则会中断main.cc。但是main.cc仍然可以编译!

main.cc中断的原因是,即使types.h取决于main.cc中的声明,它也不包含types.h。前向声明使之成为可能。

答案 1 :(得分:0)

  

我对第一点特别感兴趣,因为我无法提出一个单一的方案,即当标头更改时,前向清理将跳过必要的重新编译。谁能告诉我这是怎么发生的?

之所以会发生,是因为如果使用类的前向声明,则依赖项跟踪器无法推断出定义该类的头文件中的某些内容已更改。但是,在大多数情况下,这没有本质上的错误。

  

这是Google代码库所固有的吗?

关于D的已发布代码块很有意义。如果您没有#include定义D的标头,而仅提供前向声明,则对f(x)的调用将解析为f(void*),这不是您想要的。

IMO,避免仅使用头文件#include进行前向声明是一个非常昂贵的代价,只能考虑上述用例。但是,如果您有足够的硬件/软件资源来考虑#include头文件的开销不是一个因素,那么我可以看到如何证明这样的建议。

相关问题