0

I have a two different files with the same class name (here: A). Class is used in template specialization. Specialized template is used in static object initialization. I expect that compiler uses local class to solve template but as result shows it takes two times the same specialization.

Question is: How to prevent of creating such code (maybe some compiler setting to detect this) since it is really hard to debug?


------- template.h 

template <typename T>
void Test() {
    T* t = new T();    
    delete t;
}

------- classA1.cpp 

#include <iostream>
#include "template.h"

class A {
 public:
    A() {
        std::cout << "Hello I'm class A(1)" << std::endl;
    }
};

struct Tester1 {
    Tester1() {
        Test<A>();
    }
};

static Tester1 tester1;

------- classA2.cpp 

#include <iostream>
#include "template.h"

class A {
 public:
    A() {
        std::cout << "Hello I'm class A(2)" << std::endl;
    }
};

struct Tester2 {
    Tester2() {
        Test<A>();
    }
};

static Tester2 tester2;

------- main.cpp 

#include <iostream>

int main() {
    std::cout << "Hello from main!" << std::endl;
    return 0;
};

Result:

Hello I'm class A(1)
Hello I'm class A(1)
Hello from main!
Jakub
  • 19
  • 5
  • 3
    Post your compiler invocation... – Macmade Sep 24 '19 at 12:32
  • I don't think you can use the same class name twice? – RoQuOTriX Sep 24 '19 at 12:33
  • You are going to hit a wall here with your compiler. ODR violations are normally not required to issue any sort of error reporting. That said, you might be able to get an error from the linker if you use link time optimization. – NathanOliver Sep 24 '19 at 12:33
  • You break [the One Definition Rule](https://en.cppreference.com/w/cpp/language/definition#One_Definition_Rule). Please don't do that. – Some programmer dude Sep 24 '19 at 12:34
  • Clearly the results are not from a single run of main.cpp. You are running multiple files or combining them in some way that isn't shown here. Please show your actual compilation command. I imagine you are linking main with classA1 and classA2, and as they are static their constructor runs before main is called. If so, the problem would be that the linker is determining class A is already defined and using that definition. For this to happen you would have to compile into object code first then link in another go, so this can be avoided with proper compilation. – h0r53 Sep 24 '19 at 12:38

1 Answers1

0

About One Definition Rule:

Only one definition of any variable, function, class type, enumeration type or template is allowed in any one translation unit (some of these may have multiple declarations, but only one definition is allowed).

One and only one definition of a class is required to appear in any translation unit where the class is used in a way that requires it to be complete.

There can be more than one definition in a program of each of the following: class type [...] as long as all of the following is true:

[...] - each definition consists of the same sequence of tokens [...]

You're breaking ODR. For a class type, the compiler won't complain if you break ODR, but it expects that you define the class with the same sequence of tokens. Since the compiler is expecting that all of your same name classes definitions are the same, it will pick just one of them to link, then you have the behavior that you're getting. The same occurs, for example, when you define two inline functions with same name, but with different definitions, just one of the definitions will be picked.

Community
  • 1
  • 1
João Paulo
  • 6,300
  • 4
  • 51
  • 80
  • > You're breaking ODR. Yes I do. But question is if exists trick to prevent this and catch such problem during compilation? Imagine having many files with locally defined classes created by different programmers. How to guarantee that class name won't be duplicated? If compiler cannot do this - is there linker/diagostic option to list symbols and check if class name is duplicated? – Jakub Sep 24 '19 at 13:01
  • Which compiler are you using? – João Paulo Sep 24 '19 at 13:09
  • gcc version 4.8 – Jakub Sep 24 '19 at 13:10
  • On GCC, I don't know. I think there isn't a way to do it by a compiler approach, because multiple definitions are expected and for identifying such thing would require very advanced reflexive techniques. The language does not support it. I asked for the compiler, because if you were using MSVC with Visual Studio, then VS, when you ask to find all references of a token, it returns all the definition locations of that token, then you would be able to search one by one. – João Paulo Sep 24 '19 at 13:26
  • I see that gcc has some flag: -Wno-odr Warn about One Definition Rule violations during link-time optimization. Enabled by default. but it does not work in my case. – Jakub Sep 24 '19 at 13:28
  • This flag is not suitable for your case. One thing you can do is to tell the compiler to generate the assembly files, then with a script made by yourself, you search for the functions definitions and compare the generated code. It's not guaranteed to work (mainly if you're using optimization), but it's a start... – João Paulo Sep 24 '19 at 13:33
  • 1
    "brute force" solution is proposed here: https://stackoverflow.com/questions/31722473/is-there-a-way-to-detect-inline-function-odr-violations – Jakub Sep 24 '19 at 13:38