Carlj901
Carlj901

Reputation: 1411

Class defined in different translation units

As I have understood, a class can be defined in multiple translation units aslong they're identical. With that in mind, consider the following examples:

 //1.cpp

class Foo{
 public:
  int i;
};


void FooBar();

void BarFoo(){
  Foo f;
}


int main(){
 FooBar();
 BarFoo();
}

//2.cpp

class Foo{
 public:
  std::string s;
};

void FooBar(){
  Foo f;
}

This compiles and I don't get a crash.

If I do the following changes:

//1.cpp
 Foo FooBar();
//2.cpp
 Foo FooBar(){
   Foo f;
   return f;
 }

I get a crash. Why does one result in a crash and the other doesn't. Also, am I not violating ODR in the first example? If I am, why does it compile ok?

Upvotes: 1

Views: 1228

Answers (2)

Luchian Grigore
Luchian Grigore

Reputation: 258618

The program is ill-formed for the reason you stated. The compiler is not required a diagnostics, but I don't see a point in discussing reasons for a crash in an ill-formed program.

Still, let's do it:

The first example probably doesn't crash because FooBar's behavior doesn't affect the run of main. The method is called, it does something, and that's it.

In the second example, you attempt to return a Foo. FooBar returns the version of Foo defined in 2.cpp. main appears in 1.cpp so it expects the version of Foo defined in 1.cpp, which is a completely different version - different members, sizes. You most likely get a corruption on the destructor. (just a guess)

EDIT: this does break the one definition rule:

3.2 One definition rule [basic.def.odr]

6) There can be more than one definition of a class type [...] in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. [...]

  • each definition of D shall consist of the same sequence of tokens;

[...]

Upvotes: 2

Kirill Kobelev
Kirill Kobelev

Reputation: 10557

Here is how compiler/linker work:

  1. Compiler translates cpp file having the headers that are provided. It generates an .obj file. In your case the o.bj file will have references to data-struct Foo. And there will be no any other details.

  2. Linker links .obj files together. It compares only the string names. In your obj files your have the same Foo. Names match. For the linker this is the same thing.

  3. After that you start your program. Most likely it will crash. To be more specific it will show undefined behavior. It can enter infinite loop, show strange messages, etc.

It is your responsibility to provide identical headers or definitions in the cpp files into translations of every cpp file. Existing software tools cannot check this for you. This is how it works.

Upvotes: 1

Related Questions