为什么在G++多次包含时违反一个定义规则?
我不太了解链接过程,并且在模板类中,我正在为多文件汇编而苦苦挣扎。我想将定义保留在一个文件中,并在另一个文件中声明。但是经过一天的痛苦,我发现我应该将定义和声明保留在同一过渡单元中(请参阅此处)。但是我的代码仍然没有编译,如果我不弄清楚,我会发布另一个问题。
但这不是问题。问题是:一旦我阅读了“ 将定义和声明保留在同一标题中“,它被认为是不良的做法。其中一条评论说:
Include Guards防止在同一源文件中多次包含相同的标头文件。它不能防止包含多个源文件
是有意义的,直到我想用G ++中的标准库尝试一下。我尝试使用< vector>
进行操作,所以我有两个文件:
main.cpp:
#include "class.h"
#include <vector>
template class std::vector<int>;
int main()
{
std::vector<int> arr;
}
class.h:
#include <vector>
std::vector<int> a(4);
我用g ++ main.cpp class.h
和它成功地编译了。但为什么?我不是两次包括&lt; vector&gt;
,因此我有双重定义?
我在计算机上检查了标头文件,它们在同一文件中具有定义和声明。
I poorly understand the linkage process, and I'm struggling with multi-file compilation with template classes. I wanted to keep definitions in one file, declarations in another. But after a day of suffering, I found out that I should keep definitions and declarations in the same transition unit (see here). But my code still doesn't compile, and if I do not figure it out, I'll post another question.
But that's not the question. The question is: once I was reading about "keeping definitions and declarations in the same header" and it was considered as bad practice. One of the comments says:
The include guards protect against including the same header file multiple times in the same source file. It doesn't protect against inclusion over multiple source files
Makes sense, until I wanted to try this out with standard libraries in g++. I tried to do it with <vector>
, so I have two files:
main.cpp:
#include "class.h"
#include <vector>
template class std::vector<int>;
int main()
{
std::vector<int> arr;
}
class.h:
#include <vector>
std::vector<int> a(4);
I compiled with g++ main.cpp class.h
and it compiled successfully. But why? Didn't I included <vector>
twice, and therefore I have double definitions?
I checked header files on my machine, and they have definitions and declarations in the same file.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您需要区分两个类别的实体:整个程序中可能只有一个定义的实体以及每个翻译单元中可能具有单个定义的定义的实体,尽管这些定义必须相同(即令牌的序列,以及一些更多的要求)。无论如何,单个翻译单元可能只包含一个实体的定义。
参见 https://en.cppreference.com/w/cpp/cpp/language/definition 以获取细节。
大多数实体属于第一个类别,但是类,各种模板和
inline
函数属于第二个类别。这些实体不仅可以在每个翻译单元中定义这些实体,而且通常需要在每个翻译单元中使用它们定义需要。这就是为什么他们的定义通常属于标头文件,而第一类的实体的定义从不属于标题文件。std :: vector
是类模板,因此可以在每个翻译单元中定义IT及其成员功能。尚不清楚您使用编译器调用
g ++ main.cpp class.h
是什么意图elseclass.h
由于其文件结束(请参阅您的问题下的注释)。在
main.cpp
的汇编单元中,您不包括std :: vector
或其成员的两个定义,尽管您有两个#unclude include lt; vector&gtector&gtector&gt; < /代码>指令,因为需要标准库来防止这种情况发生。它可以EG使用标头警卫作为用户代码可以实现相同的保证。
如果
class.h
也将作为翻译单元编译,那么仍然没有问题,因为std :: vector
及其成员是模板的实体,因此可以在此翻译单元中再次定义它们。请注意,从技术上讲,标准库不受语言规则的约束。它可能根本不用C ++写。在这种情况下,只要用户程序符合语言规则,它就必须为用户正确工作,无论其包含如何。
另请注意,显式实例化定义
在您使用的方式上毫无意义。仅当类模板的成员是针对上述典型用法而不是在标题中定义的,而是一个单个翻译单元(但对于标准库的情况)或加快汇编时间,在此中,才需要这种情况应该在其他翻译单元中有明确的实例化声明,以防止隐式实例化。
You need to differentiate between two categories of entities: Those that may have only one definition in the whole program and those that may have a single definition in each translation unit, although these definitions must be identical (i.e. same sequence of tokens plus some more requirements). In any case a single translation unit may contain only one definition of an entity.
See https://en.cppreference.com/w/cpp/language/definition for the details.
Most entities belong to the first category, but classes, templates of all kinds and
inline
functions belong to the second one. Not only can these entities be defined in every translation unit, but they typically need to be defined in every translation unit using them. That's why their definitions typically belong in header files, while definitions of entities of the first category never belong in a header file.std::vector
is a class template, so it and its member functions can be defined in each translation unit once.It is not clear what you intention with the compiler invocation
g++ main.cpp class.h
is, but it actually compiles only one translation unit (main.cpp
) and does something else forclass.h
because of its file ending (see comments under your question).In the compilation unit for
main.cpp
you are not including two definitions ofstd::vector
or its members, although you have two#include<vector>
directives, because the standard library is required to prevent this from happening. It could e.g. use header guards as user code would to achieve the same guarantee.If
class.h
would also be compiled as a translation unit, then there still wouldn't be an issue, sincestd::vector
and its members are templated entities and so they can be defined again in this translation unit.Note that technically the standard library is not bound by the language rules. It may not be written in C++ at all. In that case it just has to work correctly for the user, no matter how it is included, as long as the user program is in accordance with the language rules.
Also note that the explicit instantiation definition
is pointless in the way you are using it. It is only required if the members of the class template are, against the typical usage mentioned above, not defined in the header but a single translation unit (but that is never the case for the standard library) or to speed up compilation time, in which case there should be an explicit instantiation declaration in the other translation units to prevent implicit instantiation.