简体   繁体   English

前瞻性声明的缺点是什么?

[英]What are the drawbacks of forward declaration?

I am wondering if there is any drawback for using forward declarations in all places when possible. 我想知道在可能的情况下在所有地方使用前向声明是否有任何缺点。 This is if my header contains only declarations. 这是我的标题只包含声明。

As far as I understand, using forward declaration speeds up compile time, but I don't know of any drawbacks as such. 据我所知,使用前向声明可加快编译时间,但我不知道有什么缺点。

Example: 例:

ah: 啊:

Class A
{
};

bh: BH:

// Should I use and include "a.h" in the cpp file (e.g., a.cpp)
Class A;
Class B
{
    doSomething(A *a);
    A *myA;
};

Or is it better to use 或者它是否更好用

bh: BH:

#include "a.h"

Class B
{
    doSomething(A *a);
    A *myA;
};

Using forward declarations improves decoupling . 使用前向声明可以改善解耦 If you can avoid including "Ah" by using a forward declaration, it is a good idea to use forward declaration. 如果你可以通过使用前向声明来避免包含"Ah" ,那么使用前向声明是个好主意。 It is better not only because your builds run faster (after all, preprocessed headers can deal with compiler efficiency pretty well) but because it tells the readers of your declaration that the structure of your class B does not depend on knowing anything about your class A , other than that it exists * . 最好不仅因为你的构建运行得更快(毕竟,预处理的头文件可以很好地处理编译器效率),但是因为它告诉读者你的声明,你的B类结构不依赖于你对AA了解A除了存在之外*

EDIT (to answer your question) The only downside to forward declarations that I know is that you cannot use them in all situations: for example, a declaration similar to this: 编辑 (回答你的问题)我知道转发声明的唯一缺点是你不能在所有情况下使用它们:例如,类似于这样的声明:

class B
{
    A myA[10];
};

would not compile, because the compiler needs to know the size of A . 不会编译,因为编译器需要知道A的大小。 However, the compiler finds such issues very reliably, and informs you about them in unambiguous terms. 但是,编译器可以非常可靠地发现这些问题,并以明确的方式通知您。

* The implementation of class B could very well depend on knowing the details of class A . * B类的实施很可能取决于了解A类的细节。 However, this dependency becomes an implementation detail of B hidden from the users of your class; 但是,这种依赖关系成为您的类用户隐藏的B的实现细节; you can change it at any time without breaking the code dependent upon class B . 您可以随时更改它,而不会破坏依赖于B类的代码。

Forward declaration is the only way to break the cyclic inclusion. 前向声明是打破循环包含的唯一方法。

This is the main drawback when not used carefully, I think. 我认为,如果不小心使用,这是主要的缺点。 I worked in a large project where forward declarations are made whenever possible. 我在一个大型项目中工作,尽可能做出前瞻性声明。 Cyclic dependencies were a real problem in the end. 循环依赖最终是一个真正的问题。

using forward declaration speeds up compiler time 使用前向声明可加快编译时间

This is partially true, because the compiler (and preprocessor) do not need to parse included headers in every file you include this header. 这是部分正确的,因为编译器(和预处理器)不需要在包含此标头的每个文件中解析包含的标头。

The real improvement you see when you change the header and need to recompile. 更改标题并需要重新编译时看到的真正改进。

Forward declaration is the only way to break the cyclic inclusion. 前向声明是打破循环包含的唯一方法。

I'll speak in practical terms. 我会用实际的话说。 Pros: 优点:

  1. Avoids circular compiler dependencies. 避免循环编译器依赖性。 The way you wrote the code above would not even compile otherwise unless you put A and B in the same header. 除非你把A和B放在同一个标​​题中,否则你编写上面代码的方式甚至都不会编译。

  2. It avoids compile-time dependencies. 它避免了编译时依赖性。 You're allowed to change ah without recompiling units that include bh For the same reason, it speeds up builds in general. 你可以改变啊,而无需重新编译包含bh的单位。出于同样的原因,它可以加速构建。 To find out more on this subject, I recommend looking up the Pimpl idiom. 要了解有关此主题的更多信息,我建议查找Pimpl习语。

Cons: 缺点:

  1. Applied heavily in this way you have above, your general source files will probably need to include more headers (we cannot instantiate or work with A simply by including Bh). 以这种方式大量应用,您的一般源文件可能需要包含更多标题(我们无法通过包含Bh来实例化或使用A)。 To me, that's a worthwhile exchange for faster builds. 对我而言,这对于更快的构建来说是一次有价值的交流。

  2. This is probably the biggest con which is that it can come with some runtime overhead depending on what you are doing. 这可能是最大的骗局,它可能会带来一些运行时开销,具体取决于您正在做什么。 In the example you gave, B cannot directly store A as a value. 在您给出的示例中,B不能直接将A存储为值。 It involves a level of indirection, which may also imply an extra heap allocation/deallocation if B is the memory manager of A (the same would be true of a pimpl). 它涉及一个间接级别,如果B是A的内存管理器(对于pimpl也是如此),这也可能意味着额外的堆分配/释放。 Whether this overhead is trivial or not is where you have to draw the line, and it's worth remembering that maintainability and developer productivity is definitely more important than a micro-optimization which won't even be noticeable to the user. 这种开销是否微不足道是您必须绘制线条的地方,值得记住的是,可维护性和开发人员的工作效率肯定比微观优化更重要,微观优化对用户来说甚至都不会引起注意。 I wouldn't use this as a reason to rule out this practice unless it is definitely proving to be a bottleneck or you know well in advance that the cost of a heap allocation/deallocation or pointer indirection is going to be a non-trivial overhead. 我不会用这个作为排除这种做法的理由,除非它肯定被证明是瓶颈或你事先知道堆分配/释放或指针间接的成本将是一个非平凡的开销。

The only drawback that comes to mind is that forward declarations require pointers. 想到的唯一缺点是前向声明需要指针。 Therefore they may not be initialized and therefore could cause a null reference exception. 因此,它们可能未初始化,因此可能导致空引用异常。 As the coding standard that I currently use, requires all pointers require a null reference check if can add allot of code. 作为我目前使用的编码标准,要求所有指针都需要空引用检查是否可以添加分配代码。 I started to get around this with a Design By Contract invariants; 我开始使用Design By Contract不变量来解决这个问题。 then I can assert that anything initialized in the constructor never be null. 然后我可以断言在构造函数中初始化的任何东西都不会为null。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM