6

Citing C++ Draft N4713:

Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program outside of a discarded statement (9.4.1); no diagnostic required. The definition can appear explicitly in the program, it can be found in the standard or a user-defined library, or (when appropriate) it is implicitly defined (see 15.1, 15.4 and 15.8). An inline function or variable shall be defined in every translation unit in which it is odr-used outside of a discarded statement.

In C++ versions prior to C++17, I can get around this restriction by just declaring my functions inline. C++17 adds the same feature for variables.

Furthermore, it seems to me that the inline-Keyword does not serve another purpose apart from making it possible to ignore the ODR.

So, why isn't this whole rule just abandoned for C++17 ? I can't see the purpose of a rule that can be turned off.

Ricardo
  • 245
  • 1
  • 9
  • 10
    Because if it's abandoned, then what happens when you have a conflict in symbols with several definitions of the same stuff with different implementation across translation units? – Matthieu Brucher Feb 08 '19 at 14:18
  • 5
    @Ricardo Why should it be abandoned? – L. F. Feb 08 '19 at 14:21
  • Why would you want to "get round" a restriction that protects you? – Galik Feb 08 '19 at 15:27
  • Even with future module, we can break ODR :-/ – Jarod42 Feb 08 '19 at 16:51
  • Even with `inline`, the sources for the multiple definitions must be identical, so in that sense there can still only be one definition; it’s just duplicated in several translation units. – molbdnilo Feb 08 '19 at 17:16
  • @Jarod42 but with modules - violation of ODR should (thats my guess) be recognized at compilation time, according to http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1103r2.pdf: `A variable, function, class type, enumeration type, or template shall not be defined where a prior definition is reachable (100.6)`. So maybe ODR violations will be finally compiler errors. – marcinj Mar 28 '19 at 19:07
  • @marcinj: Some ODR violations would probably be easily detected with modules, but we can still break ODR in so many ways. – Jarod42 Mar 28 '19 at 20:10

4 Answers4

15

"Turning off" the ODR with inline is not free: the definition of an inline entity must be present in every translation unit. Note that this implies that any change to its definition causes re-compilation of every compilation unit that uses it. This would be particularly unpleasant when the function is part of some library many / big projects depend upon.

Non-inline functions, on the other hand, live in just one compilation unit and are referenced via some symbol by the linker when needed elsewhere. Complying with the ODR guarantees that symbol is not ambiguous.

Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
  • 3
    ... and that definition must be exactly the same in all translation units. – rustyx Feb 08 '19 at 14:33
  • 1
    @rustyx True. Of course, `inline` does not really turn off the ODR, that's why I out that in quotes. Those exact details of the `inline` semantics are not really relevant in the scope of this relatively high-level Q/A though IMO, so I would prefer to skip over them for the sake of brevity and clarity. – Baum mit Augen Feb 08 '19 at 14:36
  • 8
    The ODR doesn't **guarantee** that a symbol is not ambiguous; it **requires** that it is not ambiguous. The burden is on the programmer. ODR violations do not have to be diagnosed, and they result in undefined behavior. One practical result is that when you have two different definitions of the "same" function you don't know which one will get linked in. – Pete Becker Feb 08 '19 at 15:27
  • @PeteBecker That would probably be a language problem on my part. Tried to fix it. – Baum mit Augen Feb 08 '19 at 15:41
  • @BaummitAugen -- yes, that's better. I'll leave my comment as an elaboration. – Pete Becker Feb 08 '19 at 15:58
  • @PeteBecker Thanks. I thought compliance was implicit, like "Traffic law guarantees you can safely cross a green light *(unless someone runs a red, implicitly)*". You learn something new every day. :) – Baum mit Augen Feb 08 '19 at 16:01
5

inline is dangerous and expensive.

It is expensive because every compilation unit that uses something now depends on the definition of the thing. So change the body? Recompile every user of it.

It is dangerous because if two inline definitions disagree, your program is IF-NDR (ill formed, no diagnostic required).

Without inline, two definitions cause an ill formed program, but the compiler must provide a diagnostic; usually a hard error.

inline turns off that extremely useful warning.

If every compiler was capable of converting the IF-NDR of different inline definitions into a diagnostic error message you'd have more of a case. So long as that proves difficult and/or not implemented, inline is a "activate unsafe mode!" option. Making it default would be counter productive.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • To expound on Yakk's point that `inline` is expensive: if the programmer opts-in to use an inline without profiling and assessing the performance gain, then the expense (in any moderate sized project or larger) far outweighs the unknown performance gain (if any). And "Whole Program Optimization" (WPO) or "Link Time Optimization" (LTO) may make any such expensive gain moot, for those executables that can leverage WPO or LTO. Avoid `inline` unless it has a measurable benefit, or if your project is so small compiling overhead is a non-issue, or if your time is free. – Eljay Feb 08 '19 at 17:12
  • @Eljay or when it need to be defined in header. – apple apple Apr 23 '22 at 17:28
1

The trade-off is that you need the definition of an inline function everywhere it's used. If you want that, just put your whole program in a single .cpp file.

The ODR is what you need to have separate compilation, and that is still useful.

MSalters
  • 173,980
  • 10
  • 155
  • 350
1

From cppreference:

One and only one definition of every non-inline function or variable that is odr-used (see below) is required to appear in the entire program (including any standard and user-defined libraries). The compiler is not required to diagnose this violation, but the behavior of the program that violates it is undefined.

Declaring a function as inline does not "ignore" ODR, but it causes each appearance of the function to be its own entity that needs a definition in each translation unit where it is used. Small, but significant difference. ODR is still required to have seperate translation units.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185