I am doing a C++ coding practice in Visual Studio and keep having this problem shown as title. I know where the problem happens but I don't why it happens and how to solve it. Please help me with this.
class_templete.h
typedef std::string QuestionName;
class ClassTemplete
{
public:
ClassTemplete(Question iQuestionName);
private
static std::map<QuestionName,ClassTemplete *> questionName_questionPointer_map_;
}
class_templete.cpp
map<QuestionName, ClassTemplete *> ClassTemplete::questionName_questionPointer_map_;
ClassTemplete::ClassTemplete(QuestionName iQuestionName)
{
ClassTemplete::questionName_questionPointer_map_[iQuestionName] = this;
}
chapter1_question1.h
class C1Q1 : public ClassTemplete
{
public:
C1Q1(QuestionName iQuestionName) : ClassTemplete(iQuestionName) {};
private:
static QuestionName question_name_;
static C1Q1 question_instance_;
}
chapter1_question1.cpp
QuestionName C1Q1::question_name_ = "C1Q1";
C1Q1 C1Q1::question_instance_(C1Q1::question_name_);
I found out that problem happens at this place when I run the program:
ClassTemplete::questionName_questionPointer_map_[iQuestionName] = this;
However, I cannot explain why it happens.
Please feel free to contact me if more information is required.
Kind regards,
Yi Ji
Where is QuestionName C1Q1:::question_name_ located relative to ClassTemplate::questionName_questionPointer_map_? They seem to be both variables with static storage duration, i.e., they are constructed before main() is run. However, the C++ compiler/linker orders the construction of such global objects only with one translation unit (in which case the objects are constructed top to bottom), not between translation units (in which case the objects are constructed in a random order).
You problem looks as if ClassTemplate::questionName_questionPointer_map would be constructed after C1Q1::question_name_. That is, when C1Q1::question_name_ is constructed, an object which is not, yet, constructed is being accessed.
The conventional fix is to make the static object other objects depend on not an object but rather a function with a local static variable to which a reference is returned:
std::map<QuestionName,ClassTemplete *>&
ClassTemplete::questionName_questionPointer_map_() {
static std::map<QuestionName,ClassTemplete *> rc;
return rc;
}
(note that this construction is not thread-safe when you don't use C++11; it is thread-safe when using C++11).
You have to use std::map::insert, you can't do ClassTemplete::questionName_questionPointer_map_[iQuestionName] = this; when you insert a new key in the map.
This code should work:
ClassTemplete::questionName_questionPointer_map_.insert(std::make_pair(iQuestionName, this));
Related
First things first, I think it will make more sense to see my code. Header:
#include <vector>
#include "GUIItem.h"
class WindowManager
{
private:
static WindowManager* s_wndmgr; //A singleton maintains a pointer to itself as a class variable
std::vector<GUIItem*> m_guilist; //storage for gui item
//...
public:
static void Create();
static void Destroy();
static inline WindowManager* Get()
{
return s_wndmgr;
}
static void addItem(GUIItem *newGUIItem);
};
And the class:
#include "WindowManager.h"
#include "GUIButton.h"
WindowManager* WindowManager::s_wndmgr = NULL;
WindowManager::WindowManager()
{
s_wndmgr = NULL;
}
WindowManager::~WindowManager()
{
//Cleanup other stuff if necessary
delete s_wndmgr;
}
void WindowManager::Create()
{
if ( !s_wndmgr ) s_wndmgr = new WindowManager();
GUIButton *m_btn1 = new GUIButton();
addItem(m_btn1);
}
void WindowManager::Destroy()
{
if ( s_wndmgr ) delete s_wndmgr;
}
void WindowManager::addItem(GUIItem * newGUIItem)
{
m_guilist.push_back(newGUIItem);
}
Hopefully it makes some kind of sense. I'm trying to create a simple gui framework from scratch in OpenGL and this is a simple window manager. My issue is with m_guilist which should be accessible so that new GUIItems can be added to it such as happens in Create (GUIItem being a base class from which others inherit, such as GUIButton).
In this case I'm using addItem in order to append items to the list but I'm running into the a nonstatic member reference must be relative to a specific object error regarding the line inside addItem. I'm a little confused as to why this is the case. I understand that making addItem static is the reason for this error, but that was done in order for it to be called from within Create. Is there a way around this?
Sorry, this is quite the poor question and my grasp of C++ isn't great yet though I'm getting there. Any thoughts on this? Something tells me I'd be better to leave the Create function alone and create another nonstatic function to create my GUIItems and add them to the list.
addItem is a static function, which does not not operate on any instance of WindowManager. It can not access m_guilist, which is non-static without an instance.
Maybe you just want:
Get()->m_guilist.push_back(newGUIItem);
But you're starting to make the interface static, that's kind of hybrid. It's usually that addItem is non-static and you call it with the instance you acquire by WindowManager::Get().
Yet, WindowManager doesn't have inaccessible or deleted constructor to qualify as a singleton class. Ways to implement a Singleton design pattern.
Here is the code, simplified...
//A class used in the next class, Nothing much to worry about
class BasicLogger{
//...
};
Below is my main class. It has two member you need to look at: A static member(called log) of its own type.
And, a container (called repo) for holding objects of the above class. repo's items are accessible using operator[] overload:
class Logger {
protected:
// repository of profilers. each profiler is distinguished by a file name!
std::map<const std::string, boost::shared_ptr<BasicLogger> > repo;
public:
Logger(){} //breakpoints never reach here. why?
//universal singleton-like access to this class
static Logger log;
//returns a member stored in the above 'repo'
virtual BasicLogger & operator[](const std::string &key);
};
The problem comes from this method:
BasicLogger & Logger::operator[](const std::string &key)
{
std::map<std::string, boost::shared_ptr<BasicLogger> >::iterator it = repo.find(key);
if(it == repo.end()){
std::cout << "creating a new Logger for " << key << std::endl;
boost::shared_ptr<BasicLogger> t(new LogEngine(key));
std::map<const std::string, boost::shared_ptr<BasicLogger> > repo_debug;//just for debug
repo_debug.insert(std::make_pair(key,t));//ok
repo.insert(std::make_pair(key,t));//seg fault
return *t;
}
return *it->second;
}
and last piece of information: Throughout the project, items in repo container are accessed like below.
namespace{
BasicLogger & logger = Logger::log["path_set"];
}
Problem:
The problem is that at the beginning of program, before anything, the control goes directly to BasicLogger & logger = Logger::log["path_set"];
Q1: why exactly does the control go here first? just because log is static or anonymous namespaces are also attended initially?
Anyways,
so when the operator[] is executed, repo seems to be uninitialized. I added a local dummy variable(repo_debug) with the same signature as repo. and observed their value using gdb:
//local repo_debug
Details:{... _M_header = {... _M_parent = 0x0, _M_left = 0x7fffffffdc08, _M_right = 0x7fffffffdc08}, _M_node_count = 0}}}
//main 'repo'
Details:{..._M_parent = 0x0, _M_left = 0x0, _M_right = 0x0}, _M_node_count = 0}}}
Q2. why is repo uninitialized? Basically, why Logger's constructor is not called?
Q3. suggestions to take care of this problem is highly appreciated.
Thanks
Q1: Presumably the declarations are in separate compilation units. Static initialization order across compilation units is implementation defined. So, it's this way due to chance. I'd say lucky chance because the other way you would have initially thought that it works only to find that it breaks on another cpu / compiler / os later on.
Q2: Because logger in the anonymous namespace was initialized first causing a segfault which prevents the static log from ever initializing.
Q3. You could avoid the problem by avoiding singletons in your design. But if you want singletons, one way to avoid static initialization order fiasco is Construct On First Use Idiom:
Logger& Logger::log() {
static Logger* log = new Logger();
return *log;
}
The drawback is that the dynamically allocated object is never actually freed (singletons would be freed at the end of the program anyway, but might be a problem if you run without an OS)
Thread safety of initialization of static locals is guaranteed by the standard in ยง6.7/4 (c++11 draft):
...Otherwise such a variable is
initialized the first time control passes through its declaration; such a variable is considered initialized upon
the completion of its initialization. If the initialization exits by throwing an exception, the initialization
is not complete, so it will be tried again the next time control enters the declaration. If control enters
the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for
completion of the initialization.
In earlier standards and in visual c++, you can avoid concurrency issues by making sure that log is called in at least one constructor that is invoked during static initialization (which happens before main program can spawn any threads).
I'm making some changes to a legacy application (CWinApp) in Visual Studio 2013, that uses a legacy statically linked library. I'm having problems in getting const string arrays initialized in the application.
To make things easier, I've created a basic example that demonstrates the issue. The example consists of a CWinApp application (class CTestApp), that references static library MyLib.lib. CTestApp owns an object of type MyClass that's defined in MyLib. Here are some code extracts:
Main Application (CTestApp)
TestApp.h:
class CTestApp : public CWinApp
{
// --- Standard Wizard generated CWinApp stuff here ---
private:
MyClass mine;
};
TestApp.cpp:
// --- Standard Wizard generated CWinApp stuff here ---
CTestApp::CTestApp()
: mine(55)
{
}
Static Library (MyLib.lib)
MyClass.h:
#pragma once
#include <string>
const std::string ids[] =
{
"ABC",
"DEF",
"GHI"
};
const int num_ids = 3;
class MyClass
{
public:
MyClass(int id);
private:
int id;
std::string name;
};
MyClass.cpp:
#include "MyClass.h"
MyClass::MyClass(int id)
: id(id)
{
for (int i = 0; i < num_ids; ++i)
{
name += ids[i];
}
}
The problem is that when stepping through CTestApp::CTestApp into MyClass::MyClass, I find that the strings in array ids are empty. What's also strange is that the integer constant num_ids is initialized to 3 as expected. This seems to only happen for const string arrays declared in static libraries. If I declare a similar array within CTestApp itself, it is initialized by the time I step into CTestApp::CTestApp.
I also find that if I run the application and break in CTestApp::InitInstance then ids has been initialized correctly.
Is there a way to force Visual Studio to initialize const string arrays such as this before entering the member initialization section of CTestApp::CTestApp?
Not really. You can probably solve your specific case, though.
ids is a global variable with dynamic initialization.
So is your global CTestApp object.
ids is defined everywhere that includes the header. The app object is probably defined in some main file.
The order of dynamic initialization of globals in different modules (.cpp files) is unspecified by C++. It can differ from compilation to compilation, from compiler to compiler. You don't want to depend on it.
If you need to guarantee an order, the only way is to put the initialization into the same module. A single module is initialized in order of declaration.
So the solution for your specific case is: declare ids as extern in the header, and actually define it alongside your global app, just before. However, that doesn't scale as you get more classes.
Alternatively, make ids a true constant by changing it to an array of const char*. That would make it get initialized statically, which happens before dynamic initialization.
Finally, you could change mine to a (smart) pointer and only initialize it in InitInstance.
Let us assume the following class:
class FileManipulator
{
static InputTypeOne * const fileone;
InputTypeTwo *filetwo;
public:
FileManipulator( InputTypeTwo *filetwo )
{
this->filetwo = filetwo;
}
int getResult();
};
FileManipulator uses data from both files to obtain output from getResult(). This means multiple iterations over filetwo and multiple constructions of FileManipulators via iterations for different InputTypeTwo objects. Inputs are, let us say, some .csv databases. InputTypeOne remains the same for the whole task.
The program itself is multi-modular and the operation above is only its small unit.
My question is how can I handle that static field in accordance with the object-oriented paradigm and encapsulation. The field must be initialized somehow since it is not a fixed value over different program executions. As far as I understand C++ rules I cannot create a method for setting the field, but making it public and initializing it outside of any class (FileManipulator or a befriended class) seems to me at odds with the encapsulation.
What can I do then? The only thing that comes to my mind is to do it in a C manner, namely initialize it in an isolated enough compilation unit. Is it really all I can do? How would that be solved in a professional manner?
edit
I corrected pointer to constant to constant pointer, which was my initial intention.
You can write a public static method of FileManipulator that would initialize the field for you:
static void init()
{
fileone = something();
}
And then call it from main() or some place where your program is being initialized.
One way of doing this which comes to mind is:
In the .cpp file
FileManipulator::fileone = NULL;
Then modify constructor to do the following:
FileManipulator( InputTypeTwo *filetwo, InputTypeOne *initValue = NULL)
{
if(fileone == NULL)
{
fileone = initValue;
}
this->filetwo = filetwo;
}
Or you could also define an init function and make sure to call it before using the class and after the CTOR. the init function will include the logic of how to init fileone.
I've developed a game on Cocos2d-x v2 platform
I started on Android, after completely finishing the coding on Eclipse I used the same code on Xcode to create and iOS version.
After adding all the required libraries, I succeeded in compiling the code. However, the game hangs the moment it runs on an iOS device, although it runs without any problem on Android.
I tried both the emulator and an iPod, but I always get an EXC_BAD_ACCESS when accessing a static member from a static method. The static member would always point to 0x0!!
Here's an excerpt from the code:\
AppDelegate.cpp
#include "AppDelegate.h"
#include "NASEncData.h"
AppDelegate::AppDelegate()
{
ep = NASEncData::sharedUserData();
}
NASEncData.h
namespace CocosNas
{
class NASEncData : public CCObject
{
public:
static NASEncData* sharedUserData();
private:
NASEncData();
static void initXMLFilePath();
static std::string m_sFilePath;
}
}
NASEncData.cpp
#include "NASEncData.h"
NASEncData* NASEncData::sharedUserData()
{
initXMLFilePath();
// only create xml file one time
// the file exists after the programe exit
if ((! isXMLFileExist()) && (! createXMLFile()))
{
return NULL;
}
if (! m_spUserData)
{
m_spUserData = new NASEncData();
}
return m_spUserData;
}
void NASEncData::initXMLFilePath()
{
if (! m_sbIsFilePathInitialized)
{
m_sFilePath += CCFileUtils::sharedFileUtils()->getWriteablePath() + NASENCDATA_XML_FILE_NAME; <----error happens here
m_sbIsFilePathInitialized = true;
}
}
Based on the comments on your question, your problem could be the initialization order of static data. To be more specific, I think it is possible that the static AppDelegate instance gets created and initialized before the static members in the NASEncData. And this problem could also explain the fact that you are seeing different behavior on different platform, because the initialization order of unrelated static data are compiler and linker dependent.
To fix this, you could change your NASEncData like this: (note that this is only one possible fix, although if the initialization order of statics is really your problem, I think this is the simplest and best solution, apart from redesigning your code so that you don't have to rely on static members.)
NASEncData.h
namespace CocosNas
{
class NASEncData : public CCObject
{
public:
static NASEncData* sharedUserData();
private:
NASEncData();
static void initXMLFilePath();
// Note how the stuff below this line have changed
struct StaticData
{
std::string m_sFilePath;
// Put other static members here
// (e.g. m_sbIsFilePathInitialized, m_spUserData, etc.)
// Put a proper constructor here if needed
};
static StaticData & getStaticData ()
{
static StaticData s_data;
return s_data;
}
}
}
NASEncData.cpp
void NASEncData::initXMLFilePath()
{
if (! m_sbIsFilePathInitialized)
{
// Note the change in accessing m_sFilePath
// You should access all your static members like this
getStaticData().m_sFilePath +=
CCFileUtils::sharedFileUtils()->getWriteablePath() +
NASENCDATA_XML_FILE_NAME;
getStaticData().m_sbIsFilePathInitialized = true;
}
}
What this does in ensure that when you try and access your static member data, they have already been initialized. This happens because all your static member data are now defined inside a function as static, and for accessing them you have to call that function, and the compiler generates code to make sure that the first time that function is invoked (and only the first time) your data is constructed and initialized properly, which in turn means that the first time you actually try to access this data, whenever and wherever that may be from, your data is properly initialized.
It was indeed an initialization problem I just had to move the code from the construction to bool AppDelegate::applicationDidFinishLaunching() and it worked!