Can't use an STL Map in a method? [Solved]

Started by
8 comments, last by Andrew Russell 18 years, 10 months ago
Ok so I was having some problems with my STL map that I am using in my texture manager. So I whipped up a quick test. As part of my texture manager class, I have std::map<int, int> test; Yes I realise this is pointless, it is only a test. Created a quick test function void TextureManager::testfunc() { test[5] = 25; } But this crashes somewhere in the STL code. The weird thing is, it's fine if I try the same statement in the constructor. Is there something painfully obvious I have overlooked, or does anyone know a reason that could be causing this? [Edited by - Teenage Death Boy on July 1, 2005 10:25:55 AM]
Advertisement
Post more complete code.
Well, I've never tried this before, to be honest. But maybe the address can't be resolved if it's called outside of a constructor? I'm not sure, but isn't this a similar case to using a const member (which can only be initialized in a constructor's initializer list, afaik)?

Just a guess, probably get you started thinking...or something.
Things change.
Try making test[5] = 25; to test.insert( std::pair<int,int>(5,25)); and see if it crashes.
There is no reason the code he posted would fail. Until he posts it in context, it's just guesswork.
This could also happen if he's using MS Visual C++ 6.0 and he's making calls from one module (DLL or EXE) to another. If his constructor is inlined and this method is not, it would exhibit behavior like this.
	class gameTextureManager{private:	SINGLETON_DECLARE(gameTextureManager);	std::vector<int> test;public:	SINGLETON_METHODS(gameTextureManager);	void	push();};


This was the quick test class I wrote up. The class is made a singleton, using some source that a member of the forums gave me (roots from The Hero of Allacrost, source available in the CVS).

For quick reference:

/******************************************************************************
SINGLETON macros - used for turning a class into a singleton class

The following three macros turn a normal class into a singleton class. To create a singleton class, perform the following steps.

1) The class' header file must #include "utils.h"
2) Place SINGLETON_DECLARE(class_name) in the class' private section.
3) Place SINGLETON_METHODS(class_name) in the class' public section.
4) Place SINGLETON_INITIALIZE(class_name) at the top of the class' source file.
5) *REQUIRED* Implement the class' constructor and destructor (even if it does nothing).

After performing these steps, your class with have 3 functions publicly avaiable to it:

- _Create(): creates the new singleton and returns a pointer to the class object
- _Destroy(): destroys the singleton class
- _GetRefCount(): returns a pointer to the class object

Notes and Usage:

1) The constructor and destructor *MUST* be defined! If you do not implement them, then you will get a compilation error like:
> In function `SINGLETON::_Create()': undefined reference to `SINGLETON::SINGLETON[in-charge]()

2) You can not create or delete instances of this class normally. Ie, calling the constructor, copy constructor, copy assignment operator, destructor, new/new[], or delete/delete[] operators will result in a compilation error. Use the _Create(), _Destroy(), and _GetReference() functions instead.

3) The only place _Create() and _Destroy() should usually be called are in loader.cpp. But if a different section of code detects a fatal error and needs to exit the game, _Destroy() should be called for *all* Singletons.

4) FYI: _Create() and _Destroy() can be called multiple times without any problem. The only time you need to worry is if _Destroy() is called and then a part of the code tries to reference a pointer to the old singleton. Thus...

>>> ONLY CALL _Destroy() WHEN YOU ARE EXITING OR ABORTING THE ENTIRE APPLICATION!!! <<<

5) You can get a class object pointer like this: 'MYCLASS *test = MYCLASS::_GetReference();'
*****************************************************************************/

// Put in the private sector of the class definition
#define SINGLETON_DECLARE(class_name)
static class_name *_ref; class_name(); ~class_name(); class_name(const class_name&); class_name& operator=(const class_name&);

// Put in the public sector of the class definition
#define SINGLETON_METHODS(class_name) static class_name* _Create() { if (_ref == NULL) { _ref = new class_name(); } return _ref; } static void _Destroy() { if (_ref != 0) { delete _ref; ref = NULL; } } static class_name* _GetReference() { return _ref; }

// Put in the class' source file
#define SINGLETON_INITIALIZE(class_name) class_name* class_name::_ref = NULL;




In my main .cpp it is correctly set up with

gameTextureManager *textureManager = gameTextureManager::_Create();

and

gameTextureManager::_Destroy();

In the implementation of the class, I have also used

SINGLETON_INITIALIZE(gameTextureManager);

as is required.


	gameTextureManager::gameTextureManager() 	{ 		test.push_back(12);	}		gameTextureManager::~gameTextureManager() { }	void	gameTextureManager::push()	{		test.push_back(15);	}


The constructor can do it no problem, but I can't do it using the push method.
OK, that code *should* be fine. I suggest to you that your problem could be that your "this" pointer is corrupt. In other words, push() is being called on an invalid object.
gameTextureManager* t = reinterpret_cast<gameTextureManager*>(rand());t->push();
The above code is an extreme example of what could cause it.
Quote:Original post by Andrew Russell
OK, that code *should* be fine. I suggest to you that your problem could be that your "this" pointer is corrupt. In other words, push() is being called on an invalid object.
gameTextureManager* t = reinterpret_cast<gameTextureManager*>(rand());t->push();
The above code is an extreme example of what could cause it.



Well you were partially right. I was being an idiot. I _Create'd my video manager before my texture manager, and tried to use _GetReference before the texture manager had properly been constructed. Ooops ^_^ (but thank you everyone for your help)
Quote:Original post by Teenage Death Boy
Quote:Original post by Andrew Russell
OK, that code *should* be fine. I suggest to you that your problem could be that your "this" pointer is corrupt. In other words, push() is being called on an invalid object.
gameTextureManager* t = reinterpret_cast<gameTextureManager*>(rand());t->push();
The above code is an extreme example of what could cause it.



Well you were partially right. I was being an idiot. I _Create'd my video manager before my texture manager, and tried to use _GetReference before the texture manager had properly been constructed. Ooops ^_^ (but thank you everyone for your help)


Here's a tip for you then. I assume that your singleton has a static member pointer. You need to initialize that to NULL staticly. Then in your GetReference() function, you should drop in an assert to check it.

example:
class Foo{    static Foo* singleton;public:    Foo() {assert(!singleton); singleton = this;}    ~Foo() {assert(singleton); singleton = NULL;}    static Foo& GetReference()    {        assert(singleton);        return (*singleton);    }};Foo* Foo::singleton = NULL;


Suggest you use code similar to that for all your singletons. Then you will get error messages if you screw up your initialization.

The code above gives these errors (in order) - if you try and make more than one, if you try and delete when you don't have one, and when you try and get a reference when you don't have one.

This topic is closed to new replies.

Advertisement