views:

82

answers:

3

Somewhat of an academic question, but I ran into this while writing some unit tests.

My unit test framework (UnitTest++) allows you to create structs to serve as fixtures. Usually these are customized to the tests in the file, so I put them at the top of my unit test file.

//Tests1.cpp

struct MyFixture {  MyFixture() { ... do some setup things ...} };

TEST_FIXTURE(MyFixture, SomeTest)
{
  ...
} 

//Tests2.cpp

struct MyFixture { MyFixture() { ... do some other setup things, different from Tests1}};

 TEST_FIXTURE(MyFixture, SomeOtherTest)
 {
  ...
 }

However, I found recently (with VS2005 at least) that when you name the fixture struct using the same name (so now two versions of the struct exist with the same name), then one of the versions is silently thrown out. This is pretty surprising, because I have my compiler set to /W4 (highest warning level) and no warning comes out. I guess this is a name clash, and why namespaces were invented, but do I really need to wrap each of my unit test fixtures in a separate namespace? I just want to make sure I'm not missing something more fundamental.

Is there a better way to fix this - should this be happening? Shouldn't I be seeing a duplicate symbols error or something?

+7  A: 

Try sticking the classes in an anonymous namespace, you may find it less distasteful than having to create and name a new namespace for each file.

Don't have access to VS2005 and Cpp unit but this may work..

//Tests1.cpp
namepsace
{
struct MyFixture {  MyFixture() { ... do some setup things ...} };
}

TEST_FIXTURE(MyFixture, SomeTest)
{
  ...
} 


//Tests2.cpp
namespace
{
struct MyFixture { MyFixture() { ... do some other setup things, different from Tests1}};
}

TEST_FIXTURE(MyFixture, SomeOtherTest)
{
 ...
}
Michael Anderson
+1, This is the exact problem anonymous namespaces are designed to solve
Terry Mahaffey
So is it expected that one of the two fixtures would silently overwrite the other with not a word from the linker?
Joe Schneider
Forget it - I see. I was incorrectly/stupidly thinking name mangling would apply to the struct type, so the linker could tell the difference.
Joe Schneider
A: 

This is basically a consequence of the fact that classes need to be defined in header files, which leads to having redundant definitions of the class in each object file. So a linker that can handle C++ linkage has to fold redundant class declarations together and pretend that the class was declared only once.

There isn't any way for the linker to distinguish between a single class included into multiple objects and multiple classes with the same name in multiple objects.

You have to use namespaces (or a better language), to get around this.

John Knoeller
@Kornel: one of the uses of static is to make objects that are _invisible_ to the linker. The linker is certainly not able to distinguish objects that it can't see from each other. Or do you have another point?
John Knoeller
Yeah, didn't notice that the OP was referencing to types not variables
Kornel Kisielewicz
Yes, read about it. Then when you realize it doesn't apply, read about anonymous namespaces.
Terry Mahaffey
+1  A: 

The compiler only works on a single compilation unit at a time; this would be the source file and anything it #includes. Since your classes are in different files, no conflict there.

The linker puts everything together, but it doesn't know about class definitions so it doesn't see a conflict either.

Back in the days of C, it was quite common for the linker to recognize that you had two different functions with the same name and generate an error message. With inline functions and templates in C++, it can't do that anymore - different compilation units will often contain duplicates of the same function, so the linker just assumes they're the same.

Mark Ransom