I've got some trouble with static members and methods in C++.
This is the Class header:
class Decoration {
public:
//Static Methods
static void reloadList();
//Static Members
static std::unordered_map<int, Decoration> decorationMapID;
};
And in .cpp:
void Decoration::reloadList() {
sqlTable result = db->exec("SELECT id, name, description FROM decorations");
for(sqlRow r: result) {
Decoration::decorationMapID.insert(std::pair<int,Decoration>(atoi(r[0].c_str()), Decoration(r[1], r[2], atoi(r[0].c_str()))));
}
}
Now, in my mainWindow class (I'm using QT5), I call reloadList() and initialize the map.
The list is now filled in this Object.
In another Window-Class, I want to use this static list, but the list is empty. Could you explain how I have to use the static members to access the same list everywhere?
Declaration of second class:
in mainWindow.h:
ShoppingLists slDialog;
in mainWindow.cpp I call:
slDialog.setModal(true); slDialog.show();
Btw.: The whole thing is a CocktailDatabase, so my target is to have a List/Map for Cocktail-, Ingredient-, Decoration-, and Taste- Objects, which I can use without reloading it from SQLite.
1) The static member exists only once and is shared between all the instances of Decoration.
2) The question is why it is empty. Here some hints:
a) You think it is empty because some windows object was not refreshed and is not aware that your list was poupulated.
b) Your window get initiaslised before the static list is initialised
3) nevertheless an advice: don't make your static list public, especially if it has to be initialised before it's used. Use a public access function that makes sure it's initialised. Here the rough idea:
class Decoration {
public:
std::unordered_map<int, Decoration> getMap();
protected: // or even private ?
static void reloadList();
static bool loaded=false;
static std::unordered_map<int, Decoration> decorationMapID;
};
where getMap() would be something like:
if (!loaded) {
... // load the list here
loaded = true;
}
return (decorationMapID);
You are using the default-constructed value of the static variable before it had a chance to be populated. If you put breakpoints in the code that uses the value and the code that initializes it, you'll see that the latter is called after the former.
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.
This question follows on from the outcome of this one:
How to automatically maintain a list of class instances?
With reference to the previous question, I created my static list of objects static std::set< Object* > objects;
However, to avoid circular referencing between Engine and Object, I moved it out of Engine and into a separate header file. I then realised that rather than directly interacting with the list, I could use a bunch of static accessors. This way if anything is making changes to the list, I can always break on these functions.
Are there any other benefits for doing it this way? Or is this a bad way to go? I never intend to instantiate ObjectManager ever - should I be using what I believe are called 'free functions' instead to manage this std::set, with no class?
I have created a test project to keep things simple in testing this out. The Inheritor class inherits from the Object class. The code for the ObjectManager class (referenced by Main.cpp, Object and Inheritor in this case, but a very similar one would be used in my main project) is below:
ObjectManager.h:
#include <set>
class ObjectManager
{
friend class Object;
friend class Inheritor;
public:
static int ObjectCount();
static void AddObject(Object *);
static void RemoveObject(Object *);
static int InheritorCount();
static void AddInheritor(Inheritor *);
static void RemoveInheritor(Inheritor *);
static std::set<Object *>::iterator GetObjectListBegin();
static std::set<Object *>::iterator GetObjectListEnd();
static std::set<Inheritor *>::iterator GetInheritorListBegin();
static std::set<Inheritor *>::iterator GetInheritorListEnd();
private:
ObjectManager();
~ObjectManager();
};
ObjectManager.cpp:
#include "ObjectManager.h"
static std::set<Object *> objectList;
static std::set<Inheritor *> inheritorList;
ObjectManager::ObjectManager()
{
}
ObjectManager::~ObjectManager()
{
}
int ObjectManager::ObjectCount()
{
return objectList.size();
}
void ObjectManager::AddObject(Object *input)
{
objectList.insert(input);
}
void ObjectManager::RemoveObject(Object *input)
{
objectList.erase(input);
}
int ObjectManager::InheritorCount()
{
return inheritorList.size();
}
void ObjectManager::AddInheritor(Inheritor *input)
{
inheritorList.insert(input);
}
void ObjectManager::RemoveInheritor(Inheritor *input)
{
inheritorList.erase(input);
}
std::set<Object *>::iterator ObjectManager::GetObjectListBegin()
{
return objectList.begin();
}
std::set<Object *>::iterator ObjectManager::GetObjectListEnd()
{
return objectList.end();
}
std::set<Inheritor *>::iterator ObjectManager::GetInheritorListBegin()
{
return inheritorList.begin();
}
std::set<Inheritor *>::iterator ObjectManager::GetInheritorListEnd()
{
return inheritorList.end();
}
**
EDIT:
**
I have rewritten my code to remove the need for an ObjectManager.
Instead of using ObjectManager, each class I want a list of contains the static list in its source file, so Object.cpp contains static std::set<Object *> objectList; and Inheritor.cpp contains static std::set<Inheritor *> inheritorList;.
Then, each of those two classes contains a static Count() function, for getting the number of items in its respective list, GetListBegin() and GetListEnd() for getting the beginning and end of the set.
As the functions share the same name in both the base class and the derived one, Object::Count() gets the number of Object instances in its respective list, and Inheritor::Count() gets the number of Inheritor instances in its respective list.
I don't know if this is a bad way of doing this or not. Nothing can add or remove from the list outside of each respective class. My only issue is I'm not sure how to stop the static functions from being available in anything that say, inherits from Inheritor for example.
If std::set provides exactly the right interface then you can use it directly. If it doesn't (and that's usually the case: it has a very broad interface) then you should write a class or a set of functions that provide the interface you need, and implement appropriately, perhaps with std::set, perhaps with something else.
I would put this set as a private static member of Object class, which adds itself to the set in the constructor (don't forget copy constructor, if permissible). Then make a public read-only accessor to the set (return const reference).
I don't understand the meaning of your Inheritor set.
If this is a list of live objects in a game engine, I would make it a non-static member of engine class which keeps track of all its objects.
I have some classes in my project with static properties. How could I make one static method that populates a container from which these static properties read data from. How could I make one static method run first before any other static method.How do you which classes static properties get loaded first
The typical way to do this is to wrap your static object in a getter function, so that it doesn't get created until it is first used.
This way, the order is determined by the design of the program.
An example of this scheme would be the following:
class MyClass {
public:
static
MyContainer& GetTheContainer() {
static MyContainer* fgCon = new MyContainer; // happens at first demand
return *fgCon; // happens whenever MyClass::GetTheContainer() is called
}
static
SomeObj& GetFromContainerAt(const int i) {
MyContainer& c = GetTheContainer();
return c.At(i);
}
};
The rest depends on the design of your program. You could have the other classes fill the container -- as long as they use GetTheContainer, you can be sure that the container will be made first. Or you can fill the container on its creation, either by checking if it's empty (if you're sure it will only ever be empty upon creation), or by using a flag system:
MyContainer& GetTheContainer() {
static MyContainer* fgCon = new MyContainer; // happens at first demand
static bool isNew = true; // only true the first time
if (isNew) {
// fill the container
isNew = false;
}
return *fgCon; // happens whenever MyClass::GetTheContainer() is called
}
You can read more about this scheme at the C++ Faq, for example.
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!
I have written a class (AbcdBase) which holds several static objects, these include maps and a few static objects that act as "helper tools" such as plotting helper functions, objects which store constants for making tables and so on.
Separately I have other classes (DataSample and DoABCD) that need access to those static members, the twist is that DoABCD creates several instances of DataSample. What would be the correct way of coding this? Having both DataSample and DoABCD be derived classes of AbcdBase doesn't seem like the correct way (and I get Seg violations when I do that).
class AbcdBase {
private:
int init();
int status;
public:
static SampleAggregator* SampleAggregatorInst;
static PlotHelper* PlotHelperInst;
static DataSampleConst* DataSetMap;
static DataSampleConst::SampleDict* ListOfSamples;
static std::vector<std::string> ListOfPlots;
static std::vector<std::string> ListOfRegions;
static Logger* LoggerInst;
AbcdBase();
virtual ~AbcdBase();
typedef enum {
A = 1, B = 2, C = 3, D = 4
} RegionEnum;
typedef enum {
MET = 1, ETCONE20 = 2
} DimensionEnum;
ClassDef(AbcdBase, 1)
};
Is a singleton the correct way of solving this issue? so that whenever DataSample or DoABCD need access to a member of AbcdBase they instance() function gets called which returns a pointer to a private instance of AbcdBase. I feel like this would clutter the code a LOT.
Thanks
Separately I have other classes (DataSample and DoABCD) that need access to those static members
Merely declare those static member public, as you have done, and then reference them in any other code (including the code in DataSample or DoABCD:
class DataSample {
...
int GetFragle(void) {
return AbcdBase::PlotHelperInst->m_fragle;
}
...
};
No need to do anything.
They're already public, you can use AbcdBase::PlotHelperInst from ANYWHERE.