static instance of a class optimized out of existence...

  • Thread starter Thread starter Bran Kelly
  • Start date Start date
B

Bran Kelly

Hi,

I am running into something I haven't ever encountered before. I have a
static instance of a class declared in a cpp file, which seems to be
optimized (or for some other reason) out of existence. It is something like
the following:

foobar.hpp
class foobar
{
};

foobar.cpp
static foobar s_foobar;

This is part of larger chunk of code (a monostate factory, which relies upon
a object types (foobar) being statically initialized, but never actually
used directly. Note this code is loosely based on Dewhurst's firewall code
from "C++ Gotchas"), which works just fine when it is part of my unit test
framework, i.e. the static instance is actually created, and everything is
just great.
When I folded the code back into my app, foobar is never instantiated. At
first I thought I was dreaming, but as a quick hack I placed a plain ol' C
function in foobar.cpp that did nothing but access one of foobar's member
vars. When that function was placed in my main application code - poof -
foobar was suddenly instantiating into existence.

I am compiling with Visual Studio 8 and have only one "non-standard"
setting, which is "-Zm200", which I had to do because my pre-compiled header
file had surpassed the default size allowed.
It should also be noted that I am running in debug mode, with no
optimizations, running as vanilla as possible.

Is there some compiler setting that would cause such behavior? I have done a
diff between my unit test and my application and I could find no culprit.

TIA,
Bran
 
Bran said:
Hi,

I am running into something I haven't ever encountered before. I
have a static instance of a class declared in a cpp file, which seems
to be optimized (or for some other reason) out of existence. It is
something like the following:

foobar.hpp
class foobar
{
};

foobar.cpp
static foobar s_foobar;

This is part of larger chunk of code (a monostate factory, which
relies upon a object types (foobar) being statically initialized, but
never actually used directly. Note this code is loosely based on
Dewhurst's firewall code from "C++ Gotchas"), which works just fine
when it is part of my unit test framework, i.e. the static instance
is actually created, and everything is just great.
When I folded the code back into my app, foobar is never
instantiated. At first I thought I was dreaming, but as a quick hack
I placed a plain ol' C function in foobar.cpp that did nothing but
access one of foobar's member vars. When that function was placed in
my main application code - poof - foobar was suddenly instantiating
into existence.
I am compiling with Visual Studio 8 and have only one "non-standard"
setting, which is "-Zm200", which I had to do because my pre-compiled
header file had surpassed the default size allowed.
It should also be noted that I am running in debug mode, with no
optimizations, running as vanilla as possible.

Is there some compiler setting that would cause such behavior? I have
done a diff between my unit test and my application and I could find
no culprit.

Have you by chance put the module containing the static instance into a
library that's then linked into your application? If that's the case, the
linker won't even include that module unless something else in the module is
referenced externally. You might try adding the /verbose switch to the
linker command line to see if the module is being included at all - if it's
not, you'll need to force a reference to something in the module to include
it. You might use the linker option /include to do that, or simply
reference something from another module in your program.

-cd
 
Bran said:
Hi,

I am running into something I haven't ever encountered
before. I have a static instance of a class declared in a
cpp file, which seems to be optimized (or for some other
reason) out of existence. It is something like the
following:

foobar.hpp
class foobar
{
};

foobar.cpp
static foobar s_foobar;

You can try to declare it volatile, so it will effectively
stop all optimisations for the variable:

volatile static foobar s_foobar;
 
Thanks for your response, Carl, and again, my apologies for the double post.

You are right on the mark with your assessment. The static instance is,
indeed, in a separate library.
Given that each static instance in my app is a unique message type to be
used in a messaging system, any solution to this issue is very clunky,
however, forcing the symbol reference is definitely the lesser of two evils.
I have attempted to do this in numerous ways, with no success. I have tried
including foobar and foobar.obj, but neither works. I have also tried to
include both permutations in both the library where foobar resides, as well
as anything in the dependency chain, on up to where the application resides.
Still no luck.
What is the proper way to approach this? Does /include expect mangled names?
Will I be able to do the entire module (e.g. foobar.obj), or do I have to
include each static instance by name?

Thanks,
Bran
 
Hi Alex,

Nice idea. I had high hopes for it, but it doesn't work. Thanks though...
Bran
 
Thanks for your response, Carl, and again, my apologies for the double post.

You are right on the mark with your assessment. The static instance is,
indeed, in a separate library.
Given that each static instance in my app is a unique message type to be
used in a messaging system, any solution to this issue is very clunky,
however, forcing the symbol reference is definitely the lesser of two evils.
I have attempted to do this in numerous ways, with no success. I have tried
including foobar and foobar.obj, but neither works. I have also tried to
include both permutations in both the library where foobar resides, as well
as anything in the dependency chain, on up to where the application resides.
Still no luck.
What is the proper way to approach this? Does /include expect mangled names?
Will I be able to do the entire module (e.g. foobar.obj), or do I have to
include each static instance by name?

I haven't used it, but I'd expect /INCLUDE requires the mangled name. There
are alternatives to /INCLUDE:

1. Take the address of the object you wish to be included and store it in a
global variable in your main program, e.g.

static X* p = &lib_object;

As the library author, you could collect these in a .cpp file, compile them
into a .obj file, and require users to link the .obj file; this is similar
to what MS does with the .obj files you'll find in VC's lib directory.

2. Transform your static library into a DLL.
 
Thanks for your suggestions, Doug.
If anyone is interested, I will explain the solution I chose for this
problem, building upon Doug's solution.

Given that I am writing a cross-platform package, using DLL's are not an
option.
Also, this is a commercial package, so I don't want to place any unnecessary
burdens on the user if I can avoid it.
So, what I did was to create a separate library, which I called LibLink,
that is the repository for all the libraries' static instance pointers as
described by Doug, e.g.

In LibLink.cpp:
namespace MyPackage
{
static Foobar* pFoo = &s_Foobar;
}

All libraries in the package have a dependency to LibLink, making it the
apex of the dependency pyramid. So, the all that the end user has to do is
pull in LibLink to bring in all the static instances. For the end user, this
entire issue is completely transparent and puts no additional burdens upon
them. From a developer's perspective, it is also much cleaner and more
portable, with no compiler-specific restrictions/requirements.
Also, it may be worth noting that the static instances need to be moved from
the foobar.cpp file back out into foobar.hpp, else the cpp file in LibLink
is not able to find the static var, e.g.

In foobar.hpp:
namespace MyPackage
{
class Foobar
{
};
static Foobar s_Foobar;
}


Thanks again for your suggestions, Doug.

Bran
 
Back
Top