1

If I have two structs with the same name, but each of them is written into it's own .cpp file, should it really be undefined behavior?

///////////////////////////////
// test1.h
class Foo
{
public :
    void bar();
};

///////////////////////////////
// test2.h
class Foo2
{
public:
    void bar();
};

///////////////////////////////
// test1.cpp
#include "test1.h"

struct Test
{
    Test() :a(0){}
    int a;
};

void Foo::bar()
{
    Test t;
}

///////////////////////////////
// test2.cpp
#include "test2.h"

struct Test
{
    Test() :a(0), b(0){}
    int a, b;
};

void Foo2::bar()
{
    Test t;
}

///////////////////////////////
// main.cpp
#include "test1.h"
#include "test2.h"

int main()
{
    Foo2 f;
    f.bar();
}

I have reported it to Microsoft as a bug here, but they responded, that this is undefined. Is it really? It look weird to me.

relaxxx
  • 7,566
  • 8
  • 37
  • 64
  • 1
    possible duplicate of [What exactly is One Definition Rule in C++?](http://stackoverflow.com/questions/4192170/what-exactly-is-one-definition-rule-in-c) – user657267 Apr 18 '14 at 06:17
  • You can resolve this putting them in an anonymous namespace. – user657267 Apr 18 '14 at 06:18
  • 1
    @user657267: Although the answers to that question only describe the ODR within a single translation unit (C++11 3.2/3), which doesn't apply to this question about multiple translation units (covered by C++11 3.2/5). – Mike Seymour Apr 18 '14 at 06:24
  • You should probably avoid multiple structs with the same name that's not the best practice. If they are only relevant to a specific class, make them internal. – o_weisman Apr 18 '14 at 06:24
  • compiles and links with no errors in Visual Studio 2010... – Alexander Tobias Bockstaller Apr 18 '14 at 06:24
  • 2
    This code does not violate the ODR, so I wouldn't consider it a duplicate of that. – M.M Apr 18 '14 at 06:24
  • 1
    @AlexanderTobiasHeinrich: Indeed, many compilers won't diagnose ODR violations like this. It still gives undefined behaviour though. – Mike Seymour Apr 18 '14 at 06:25
  • 3
    @MattMcNabb: It does violate the ODR, just not the part of the ODR described in the other question. – Mike Seymour Apr 18 '14 at 06:26
  • So putting `Test` into an anonymous namespace resolves this? If it's that simple, why don't compilers do it implicitly if they find a definition that is referenced only inside a single translation unit? – Alexander Tobias Bockstaller Apr 18 '14 at 06:30
  • 2
    @AlexanderTobiasHeinrich because the compiler can't be sure that the definition will not need to be accessible during linking with other units. – user657267 Apr 18 '14 at 06:32
  • OK, I think the exact nature of the violation is that the two `Test`s have different constructors, so there are two functions of the same name but with different bodies. – M.M Apr 18 '14 at 06:37
  • @AlexanderTobiasHeinrich: Because translation units are (intended to be) translated independently of each other, hence the name "unit". The compiler doesn't know whether or not other units might use this class - even if it sees that it's defined in the source file not a header (which, after preprocessing, it shouldn't), and makes the assumption that no other unit will include the source file (which you can't really assume), other units can still use the class in limited ways by declaring the name. – Mike Seymour Apr 18 '14 at 06:38
  • 1
    @MattMcNabb : No, the exact nature is that the two definitions aren't token-by-token identical. You could e.g. add a redundant `private:` in one and that alone causes an ODR violation. – MSalters Apr 18 '14 at 06:54

1 Answers1

3

This does indeed give undefined behaviour. Part of the One Definition Rule states that, if you define the same class with external linkage in multiple translation units, the definitions must be identical. (The exact wording of the rule is rather long-winded, so I won't quote it; see C++11 3.2/5 if you want the gory details). By defining Test differently in two translation units, you break this rule.

The simplest way to avoid name clashes like this is to put definitions that should be local to a file inside an unnamed namespace:

namespace {
    struct Test {
        // whatever
    };
}
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644