Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoiding an "inheritance by dominance" warning for a mocked std::fstream class

I am using googlemock to mock out an std::fstream object in my unit tests, like this:

TEST_F(SomeTest, SomethingIsDoneCorrectly)
{
    class MockFstream : public std::fstream {};
    MockFstream lMockFstream;
    // Expectations and assertions here
}

When I compile I get the following warnings:

Warning 1 warning C4250: 'SomeTest_SomethingIsDoneCorrectly_Test::TestBody::MockFstream' : inherits 'std::basic_istream<_Elem,_Traits>::std::basic_istream<_Elem,_Traits>::_Add_vtordisp1' via dominance

Warning 2 warning C4250: 'SomeTest_SomethingIsDoneCorrectly_Test::TestBody::MockFstream' : inherits 'std::basic_ostream<_Elem,_Traits>::std::basic_ostream<_Elem,_Traits>::_Add_vtordisp2' via dominance

I'd prefer clean build output, so I want to suppress these specific warnings, but I'm writing cross-platform code, so I'd also prefer to avoid compiler-specific #pragmas.

Is there something I can do in the googlemock object that will hide these warnings?

like image 407
sourcenouveau Avatar asked Jan 23 '13 18:01

sourcenouveau


1 Answers

It turns out that these warnings are a side-effect from some quirks in the Microsoft C++ STL. I've quoted an explanation from the relevant Microsoft Connect issue below.

My solution was simply to implement empty versions of the inherited functions in my mock:

TEST_F(SomeTest, SomethingIsDoneCorrectly)
{
    class MockFstream : public std::fstream
    {
        void _Add_vtordisp1() { } // Required to avoid VC++ warning C4250
        void _Add_vtordisp2() { } // Required to avoid VC++ warning C4250
    };
    MockFstream lMockFstream;
    // Expectations and assertions here
}

An explanation from Microsoft about why the warning occurs:

The story here is somewhat complicated. VC has an obscure compiler option, /vd2 (documented at http://msdn.microsoft.com/en-us/library/7sf3txa8.aspx), that fixes an obscure bug involving virtual base classes. By default, VC does something that's slightly nonconformant to the C++ Standard. /vd2 changes VC's behavior to be conformant, but this inherently affects class layout. (This layout difference is why the default hasn't been changed to be conformant - that would break users attempting to mix code compiled with different major versions of VC. Our C++ Standard Library implementation forbids such mixing, but the compiler itself is somewhat more permissive.) So if users want /vd2, they have to compile everything that way.

The twist is that the layout bug (which /vd2 fixes) affects iostreams, which uses virtual base classes, and our iostreams implementation has a separately compiled component (in msvcp100.dll/libcpmt.lib/etc.). When MS builds the STL's DLL/LIB, they're compiled the default way, without /vd2. As a result, people using /vd2 couldn't use iostreams, or they'd get bizarre crashes. Yuck.

So, we added the do-nothing virtual functions _Add_vtordisp1() and _Add_vtordisp2(). Their presence makes VC perform layout completely conformantly, regardless of /vd2 being used or not, and therefore makes iostreams usable both ways.

_Add_vtordisp1() and _Add_vtordisp2() trigger warning C4250, talking about dominance. This warning is actually completely useless - it's saying that the compiler will do exactly what the Standard requires it to do. Therefore, we suppress it in the STL's headers (which must be /W4 /analyze clean). If you're deriving from fstream, you'll need to suppress this warning in your own code.

like image 178
sourcenouveau Avatar answered Oct 19 '22 06:10

sourcenouveau