Re: include file question
On Wed, 25 Mar 2009 02:53:12 -0500, Joseph M. Newcomer
<newcomer@flounder.com> wrote:
See below...
On Tue, 24 Mar 2009 13:41:42 -0500, "Doug Harrison [MVP]" <dsh@mvps.org> wrote:
On Tue, 24 Mar 2009 09:33:58 -0700 (PDT), Ajay <ajaykalra@yahoo.com> wrote:
Wont this result in a compiler error even if I didnt use anonymous
namespace?
I haven't made that mistake since VC4, and it did not detect it. Concerning
ODR violations, the main thing I remember from the standard is, "No
diagnostic required."
Here's a program which violates the ODR, compiles fine in VC 2008, but
either prints garbage (no optimizations) or crashes (/O2) when run:
// cl -EHsc a1.cpp a2.cpp or
// cl -EHsc -O2 a1.cpp a2.cpp
// a1.cpp
#include <string>
struct A
{
std::string s;
};
static A a = { "s" };
void print();
int main()
{
A a2 = a;
print();
}
****
But 'print' takes no arguments, and the struct A here is local to this module...
****
It's (naively) intended to be local, but it's totally global! The fact that
it appears in a .cpp file as opposed to a .h file is irrelevant, because
that distinction disappears after preprocessing anyway, and it is the
result of preprocessing that the compiler compiles. The only way to make it
local is to enclose it in an anonymous namespace.
Not sure what you're getting at WRT print(). It is intended to be exactly
what it is; it's a function defined in another file a2.cpp that prints that
translation unit's idea of the class A, which differs from a1.cpp's class
A. The point is to set up an ODR violation and see what else it takes to
trip up the compiler. As I said:
Note that both a2 initializations are necessary to elicit the problem, as
is the member s1 in a2.cpp's A. Putting the structs in anonymous namespaces
avoids the problem.
// a2.cpp
#include <string>
#include <stdio.h>
struct A
{
std::string s1;
int x;
std::string s2;
};
static A a = { "s1", 2, "s2" };
void print()
{
A a2 = a;
puts(a2.s1.c_str());
puts(a2.s2.c_str());
}
Note that both a2 initializations are necessary to elicit the problem, as
is the member s1 in a2.cpp's A. Putting the structs in anonymous namespaces
avoids the problem.
The linker may indeed detect the error for functions you write yourself,
but these compiler-generated functions (ctors) remain a problem after all
this time, and the solution is to use anonymous namespaces.
*****
Interesting...does this mean the compiler declares the constructors as global methods?
joe
You could put it that way. These classes as written exist in the global
namespace, so their member functions can be considered to exist there as
well (still in class scope, of course). This is what's strange. Were you to
write the ctors yourself, the linker would detect the duplicate definitions
and issue an error message. It does not do this when the compiler generates
the ctors for you. I haven't looked at this since VC4, but ISTR that the
linker picked one set of these functions and use it erroneously for both
classes. While it would be nice to do better, technically it doesn't have
to be any smarter than this, because according to the ODR, there can be
only one class named "A" in the global namespace, and it's up to the
programmer to ensure the class is defined in the same way throughout the
program, "No diagnostic required."
--
Doug Harrison
Visual C++ MVP