2

Assume these two cpp files:

0.cc

#include <iostream>

class test{
 public:
 int num = 5;
};

int main(){
 test t;
 return t.num;
}

1.cc

class test{
 public:
 int num = 6; // <-- note this has a different value.
};

We compile it with g++ 0.cc 1.cc.

Initializing a member variable inside the class works since C++11. My question is how is it compiling whiteout a linker error? is it undefined behaviour? as we are breaking the one definition rule. If classes were not used this would generate a link error at compile time.

I know that defining a function within a class makes it inline so it would be ok to have multiple of them in different files, but not sure how multiple variables are ok?

Dan
  • 2,694
  • 1
  • 6
  • 19

1 Answers1

6

Yes, it's a violation of One Definition Rule and it's Undefined Behavior.

bolov
  • 72,283
  • 15
  • 145
  • 224
  • Just to confirm, the one definition rule does NOT apply in the case of member functions as the `inline` rule applies, it suspends the one-definition rule for that function and compiler gets to choose any one of the definitions at the end? (this is the case for C inline functions). – Dan Feb 22 '21 at 01:08
  • 1
    There is no "inline rule" that suspends the ODR. The whole set of rules saying how many definitions can be, where they can be and what they can be is called One Definition Rule. Paraphrasing the ODR: * only one definition can exist per TU; * for non-inline functions/variables 1 and only 1 definition must exist in the whole program; * there can be more definition in the whole program for class, inline function/variable as long as the definitions are identical. – bolov Feb 22 '21 at 01:17
  • quoting this answer: https://stackoverflow.com/a/56350537 which says: `Moving on to the linking stage. When the linker sees the inline flag, it suspends the one-definition rule for that function`, not a rule, but the behaviour. – Dan Feb 22 '21 at 01:20
  • @Dan that (part of the) answer is slightly incorrect. As I've said the rule that more definitions of an inline function/variable may exist in the whole program (§6.2.6 in N4659 C++17 draft) is part of the One Definition Rule (§6.2 One-definition rule [basic.def.odr]) – bolov Feb 22 '21 at 01:26
  • So then inline functions need to also match? and if they don't it's also an undefined behaviour? – Dan Feb 22 '21 at 02:32
  • Could I also ask, why doesn't this cause a link error in general as there are 2 different copies? – Dan Feb 22 '21 at 19:16
  • 1
    the copies must be identical. If they aren't the program is ill-formed ndr (no diagnostics required). By the time you reach the linking stage the source code could be lost so it would be impossible to check if two copies of a symbol in the binary are identical (or implementing a mechanism to do so would slow down the compilation substantially). That's why the ndr. – bolov Feb 22 '21 at 19:22
  • 1
    but doing the same with just global integers (and not using classes) would cause a `duplicate symbol error` even if values are the same. Why doesn't this happen when using classes? – Dan Feb 22 '21 at 19:28
  • 1
    As per ODR there must be 1 and only 1 definition of a global int variable in the whole program. Please read the link I posted to the ODR rules – bolov Feb 22 '21 at 21:41
  • 1
    So then it the case of my original example, it is still undefined behaviour to have two different `test` classes define the same `num` integer, regardless of the integer values being the same or not? it just that for some reason (not sure why) the linker is not complaining? – Dan Feb 23 '21 at 00:49
  • 1
    If the classes are identical token by token then it's ok. That's how you usually define classes: in a header file included in multiple TUs ending up with multiple identical definitions of a class. – bolov Feb 23 '21 at 04:37