Home > OS >  Why don't standard libraries in g violate the One Definition Rule when included multiple time
Why don't standard libraries in g violate the One Definition Rule when included multiple time

Time:04-29

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.

CodePudding user response:

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 for class.h because of its file ending (see comments under your question).

In the compilation unit for main.cpp you are not including two definitions of std::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, since std::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

template class std::vector<int>;

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.

  • Related