Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ class name collision

Tags:

c++

For the following C++ code, I'm getting unexpected behavior. The behavior was verified with recent GCC, Clang and MSVC++. To trigger it, it is required to split the code among several files.

def.h

#pragma once  template<typename T> struct Base {     void call() {hook(data);}     virtual void hook(T& arg)=0;     T data; }; 

foo.h

#pragma once void foo(); 

foo.cc

#include "foo.h" #include <iostream> #include "def.h"  struct X : Base<int> {     virtual void hook(int& arg) {std::cout << "foo " << arg << std::endl;} };   void foo() {     X x;     x.data=1;     x.call(); } 

bar.h

#pragma once void bar(); 

bar.cc

#include "bar.h"  #include <iostream> #include "def.h"  struct X : Base<double> {     virtual void hook(double& arg) {std::cout << "bar " << arg << std::endl;} };   void bar() {     X x;     x.data=1;     x.call(); } 

main.cc

#include "foo.h" #include "bar.h"  int main() {     foo();     bar();     return 0; } 

Expected output:

foo 1 bar 1 

Actual output:

bar 4.94066e-324 bar 1 

What I expected to happen:

Inside of foo.cc, an instance of X defined within foo.cc is made and through calling call(), the implementation of hook() within foo.cc is called. Same for bar.

What actually happens:

An instance of X as defined in foo.cc is made in foo(). But when calling call, it dispatches not to hook() defined in foo.cc but to hook() defined in bar.cc. This leads to corruption, as the argument to hook is still an int, not a double.

The problem can be solved by putting definition of X within foo.cc in an other namespace than definition of X within bar.cc

So finally the question: There is no compiler warning about this. Neither gcc, nor clang or MSVC++ did even show a warning about this. Is that behavior valid as defined per C++ standard?

The situation seems to be a bit constructed, but it happened in a real world scenario. I was writing tests with rapidcheck, where possible actions on a unit to be tested are defined as classes. Most container classes have similar actions, so when writing tests for a queue and a vector, classes with names like "Clear", "Push" or "Pop" may come up several times. As these are only required locally, I've put them in directly in the sources where the tests are execute.

like image 675
Johannes Avatar asked Jul 03 '18 12:07

Johannes


People also ask

What is name collision in C++?

Similarly, C++ requires that all identifiers be non-ambiguous. If two identical identifiers are introduced into the same program in a way that the compiler or linker can't tell them apart, the compiler or linker will produce an error. This error is generally referred to as a naming collision (or naming conflict).

What is name collision in programming?

In computer programming, a name collision is the nomenclature problem that occurs when the same variable name is used for different things in two separate areas that are joined, merged, or otherwise go from occupying separate namespaces to sharing one.


Video Answer


1 Answers

The program is Ill-formed, because it violates the One-Definition Rule by having two different definitions for class X. So it is not a valid C++ program. Note that the standard specifically allows compilers not to diagnose this violation. So the compilers are conforming, but the program is not valid C++ and as such has Undefined Behaviour when executed (and thus anything can happen).

like image 116
Angew is no longer proud of SO Avatar answered Sep 19 '22 07:09

Angew is no longer proud of SO