static initialization access violation error

M

marvind

I think I am running into the static initialization problem but I do
not understand why.

I am trying to parse a configuration file. To make this parser generic
I register callbacks for various section keywords in the configuration
file. I want to share this map of callbacks across multiple instances
of the config file (for example, when I merge two files). Whenever I
introduce a new section in the configuration file, I define a new class
for this section and also register the new callback for this section
with a new keyword.

I get an access violation exception when I step through this code and I
see the callback map Root() is uninitialized. Since I am trying to
populate the callback map only after constructing an instance of the
configuration class, why is the static callback map still
uninitialized?

Below is the basic code structure:

-- In CConfig.h
class CConfig
{
public:
...
// Note that Register is not a static function
bool Register(const std::string& skey, CallbackFn callback);
private:
// want to share this map across all instances
static std::map<std::string, CallbackFn> s_callbacks;
};


-- In CCMA.h
class CCMA : public CSection
{
...
};

-- In CCMA.cpp
// anonymous namespace
namespace
{
// ReadCMA -> new CCMA and then read relevant tags from config file
bool bRegisterCMA = G_CONFIG.Register("CMA_START", ReadCMA);
};

G_CONFIG returns either existing global pointer to CConfig after
creating a new CConfig object if necessary simulating singleton
behavior. However, we sometimes need more than one instance of CConfig
for example to merge entries from 2 different configuration files and
so we access these without using G_CONFIG (I still want to share the
callback map).

Thanks
 
P

Paul Groke

marvind said:
I think I am running into the static initialization problem but I do
not understand why.

I am trying to parse a configuration file. To make this parser generic
I register callbacks for various section keywords in the configuration
file. I want to share this map of callbacks across multiple instances
of the config file (for example, when I merge two files). Whenever I
introduce a new section in the configuration file, I define a new class
for this section and also register the new callback for this section
with a new keyword.

I get an access violation exception when I step through this code and I
see the callback map Root() is uninitialized. Since I am trying to
populate the callback map only after constructing an instance of the
configuration class, why is the static callback map still
uninitialized?

Below is the basic code structure:

-- In CConfig.h
class CConfig
{
public:
...
// Note that Register is not a static function
bool Register(const std::string& skey, CallbackFn callback);
private:
// want to share this map across all instances
static std::map<std::string, CallbackFn> s_callbacks;
};


-- In CCMA.h
class CCMA : public CSection
{
...
};

-- In CCMA.cpp
// anonymous namespace
namespace
{
// ReadCMA -> new CCMA and then read relevant tags from config file
bool bRegisterCMA = G_CONFIG.Register("CMA_START", ReadCMA);
};

G_CONFIG returns either existing global pointer to CConfig after
creating a new CConfig object if necessary simulating singleton
behavior. However, we sometimes need more than one instance of CConfig
for example to merge entries from 2 different configuration files and
so we access these without using G_CONFIG (I still want to share the
callback map).

Thanks

You need to make sure that "s_callbacks" is initialized before
"bRegisterCMA" is. One way to do so would be to grab a proper
Sincleton implementation, and make "s_callbacks" a singleto too.
The simple solution for single-threaded programs is to put all your
static data in functions that return references to the data. That way
you make sure that they are constructed in the right order.

And: you get the problem because "s_callbacks" is not initialized with
the first instance of the class, but along with all other static data.
Nonconst static members are just "globals in a namespace".
 
M

marvind

Thank you for your response.

I wrapped the callback map as you suggested:
stlCallbackMap& CallbackMap()
{
static stlCallbackMap callbackMap;
return callbackMap;
}

That "seems" to work. My mistake was that I thought that static data
members of a class are initialized before the first instance of the
class is constructed, instead of the runtime treating them as just
globals in a namespace.

Are there good "free" tools that I can use to find out if there are
such errors in the code since these errors depend on how the files are
compiled?
 
H

Howard

marvind said:
I think I am running into the static initialization problem but I do
not understand why.

I am trying to parse a configuration file. To make this parser generic
I register callbacks for various section keywords in the configuration
file. I want to share this map of callbacks across multiple instances
of the config file (for example, when I merge two files). Whenever I
introduce a new section in the configuration file, I define a new class
for this section and also register the new callback for this section
with a new keyword.

I get an access violation exception when I step through this code and I
see the callback map Root() is uninitialized. Since I am trying to
populate the callback map only after constructing an instance of the
configuration class, why is the static callback map still
uninitialized?

What's "Root()"???
Below is the basic code structure:

-- In CConfig.h
class CConfig
{
public:
...
// Note that Register is not a static function
bool Register(const std::string& skey, CallbackFn callback);
private:
// want to share this map across all instances
static std::map<std::string, CallbackFn> s_callbacks;
};


-- In CCMA.h
class CCMA : public CSection
{
...
};

-- In CCMA.cpp
// anonymous namespace
namespace
{
// ReadCMA -> new CCMA and then read relevant tags from config file
bool bRegisterCMA = G_CONFIG.Register("CMA_START", ReadCMA);
};

G_CONFIG returns either existing global pointer to CConfig after
creating a new CConfig object if necessary simulating singleton
behavior. However, we sometimes need more than one instance of CConfig
for example to merge entries from 2 different configuration files and
so we access these without using G_CONFIG (I still want to share the
callback map).

Thanks


You're assuming that s_callbacks is initialized when the first instance of
the class is created. That's not the case. You need to initialize it
yourself somewhere. That can be done in the manner of a Singleton (inside
an accessor function), or at the global level (outside the class in your
implementation file).

-Howard
 
P

Paul Groke

marvind said:
Thank you for your response.

I wrapped the callback map as you suggested:
stlCallbackMap& CallbackMap()
{
static stlCallbackMap callbackMap;
return callbackMap;
}

That "seems" to work. My mistake was that I thought that static data
members of a class are initialized before the first instance of the
class is constructed, instead of the runtime treating them as just
globals in a namespace.

Are there good "free" tools that I can use to find out if there are
such errors in the code since these errors depend on how the files are
compiled?

If it depends on how it's compiled, then it's an error - whether it
shows or not.
As for tools: asserts, logs, traces. Other than that I don't know
free tools - though they might probably exist. In my company we
use MSVC7.1 which happens to have an excellent debugger, and for
real tough cases we use Bounds-Checker and/or VTune (profiling).

You might ask in a group/forum specific to whatever OS/compiler
you are using.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top