View previous topic - View next topic |
Author |
Message |
DeveloperX 202192397
Joined: 04 May 2003 Posts: 1626 Location: Decatur, IL, USA
|
Posted: Mon Mar 02, 2009 3:01 am Post subject: On better engine design practice. |
[quote] |
|
This is more of a question to the more experienced developers that may be lingering around.
I make heavy use of the STL in my code.
I've been using the singleton pattern in my games; and as a result, I end up with code that functions fine on linux, and does not when it is built on windows.
Apparently there is a major flaw in the logic of the STL, and using singletons in the same code just causes major headaches.
Singletons, as you likely already know, are statically declared instances of a class....and if you have any STL code in them then it simply will segfault under windows.
Code: |
#include <map>
class Foo
{
public:
static Foo* GetInstance(); // returns the singleton pointer
~Foo();
// foobie handler code omitted for brevity
private:
Foo();
Foo(const Foo& rhs);
const Foo& operator=(const Foo& rhs);
std :: map <const char*, Foo*> foobies_; // this causes headaches!
};
Foo::GetInstance() { static Foo instance; return &instance; }
|
...yeah, so my question is this.
What should one use if not a singleton pattern? _________________ Principal Software Architect
Rambling Indie Games, LLC
See my professional portfolio
|
|
Back to top |
|
|
Rainer Deyke Demon Hunter
Joined: 05 Jun 2002 Posts: 672
|
Posted: Mon Mar 02, 2009 4:34 am Post subject: Re: On better engine design practice. |
[quote] |
|
I try to avoid singletons in my code. If it doesn't absolutely have to be global, I use a normal (non-singleton) object, even if the object is the only one of its class. In the rare cases where I actually want something to be global, I tend to use a regular global or static variable, without the singleton machinery.
That said, the problem with your code is probably the use of 'const char *' as a key. Use 'std::string'. (Also, if the 'Foo*' is a pointer to a dynamically allocated object, it should probably be 'boost::shared_ptr<Foo>' or another smart pointer class instead.)
|
|
Back to top |
|
|
DeveloperX 202192397
Joined: 04 May 2003 Posts: 1626 Location: Decatur, IL, USA
|
Posted: Mon Mar 02, 2009 4:50 am Post subject: Re: On better engine design practice. |
[quote] |
|
Rainer Deyke wrote: | I try to avoid singletons in my code. If it doesn't absolutely have to be global, I use a normal (non-singleton) object, even if the object is the only one of its class. In the rare cases where I actually want something to be global, I tend to use a regular global or static variable, without the singleton machinery.
That said, the problem with your code is probably the use of 'const char *' as a key. Use 'std::string'. (Also, if the 'Foo*' is a pointer to a dynamically allocated object, it should probably be 'boost::shared_ptr<Foo>' or another smart pointer class instead.) |
I don't use const char* as keys....that was just the first thought that popped into my head for an example.
I'm using an std::map of std::string to std::string _________________ Principal Software Architect
Rambling Indie Games, LLC
See my professional portfolio
|
|
Back to top |
|
|
Rainer Deyke Demon Hunter
Joined: 05 Jun 2002 Posts: 672
|
Posted: Mon Mar 02, 2009 5:19 am Post subject: |
[quote] |
|
I see. I don't suppose you have a minimal complete example program that demonstrates the problem?
Actually it wouldn't surprise if MinGW was seriously bugged, seeing as it's a Windows port of an old, old version of gcc. Visual C++ 2005 has much better C++ language support.
Simple workaround: Code: |
Foo *the_foo;
int main()
{
Foo the_foo_instance;
the_foo = &the_foo_instance;
// Program here.
the_foo = 0; // Prevent dangling pointer.
} |
|
|
Back to top |
|
|
Hajo Demon Hunter
Joined: 30 Sep 2003 Posts: 779 Location: Between chair and keyboard.
|
Posted: Mon Mar 02, 2009 9:07 am Post subject: Re: On better engine design practice. |
[quote] |
|
DeveloperX wrote: |
What should one use if not a singleton pattern? |
A singleton is a relative of the factory pattern, which ensures that only exactly one instance is created.
For creation, you can still use the factory pattern, if you need the control.
Global visibility can be achieved by either a public class variable, or a the proxy pattern, where the proxy manages access to the only one instance of the class (that was a singleton before).
(Singletons should work in C++, but I have no experience with the STL - I can only say that my former project H-World used Singeltons, albeit with selfmade templates).
|
|
Back to top |
|
|
DeveloperX 202192397
Joined: 04 May 2003 Posts: 1626 Location: Decatur, IL, USA
|
Posted: Mon Mar 02, 2009 9:17 am Post subject: |
[quote] |
|
Rainer: THANK YOU! You helped me greatly!
(if it weren't for that post above, I'd still be fighting segfaults trying to build a damned windows release of my jam-entry!) _________________ Principal Software Architect
Rambling Indie Games, LLC
See my professional portfolio
|
|
Back to top |
|
|
Tenshi Everyone's Peachy Lil' Bitch
Joined: 31 May 2002 Posts: 386 Location: Newport News
|
Posted: Mon Mar 02, 2009 4:52 pm Post subject: |
[quote] |
|
I know you already solved the problem, but I think this is relatively similar. I am coding from Windows with "cross-platform" in mind and use MingGW to compile. But when I do static pointers I do the following:
Code: |
Map *MAPENGINE;
int main() // Technically not main, but yeah
{
MAPENGINE = new Map( *TILES );
// Program
delete MAPENGINE;
exit( 0 );
}
|
Also I do use maps similar to you, and I see you say you don't use const char * as the key... which I agree with because those things can be spooky:
Code: |
map[string, Script *> *GLOBALSCRIPTLIST = NULL;
map[string, Event *> *GLOBALEVENTLIST = NULL;
|
_________________ - Jaeda
|
|
Back to top |
|
|
Mattias Gustavsson Mage
Joined: 10 Nov 2007 Posts: 457 Location: Royal Leamington Spa, UK
|
Posted: Tue Mar 03, 2009 2:01 pm Post subject: |
[quote] |
|
About using strings for keys...
I'm a bit careful about using strings of any sort (especially std::string) as keys, ever since the time I was hired to optimize a game&engine which turned out to be using hundreds of megabytes for strings (lots of duplicates) and where string comparisons,copying and allocation was right at the top of the profiling results :P
So personally I use something I call a StringId, which basically is just a pointer to a string in a global table (a hashtable for faster lookup). That way, string comparisons is just a pointer compare and duplicating a StringId is just duplicating a pointer. Creating a new StringId instance is slower (involves looking up the string in the hash table, or insert it if it doesn't exist already), but that's ok as I tend to do that mostly during initialization.
Details:
http://www.colossusentertainment.com/pixiedocs/_string_id_8h-source.html
http://www.colossusentertainment.com/pixiedocs/_string_id_8cpp-source.html _________________ www.mattiasgustavsson.com - My blog
www.rivtind.com - My Fantasy world and isometric RPG engine
www.pixieuniversity.com - Software 2D Game Engine
|
|
Back to top |
|
|
Hajo Demon Hunter
Joined: 30 Sep 2003 Posts: 779 Location: Between chair and keyboard.
|
Posted: Tue Mar 03, 2009 3:49 pm Post subject: |
[quote] |
|
The people who designed Java knew that, too, and made all string literals internalized, and gave the String class the intern() function that does just this trick ;)
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/String.html#intern()
Might be even more evidence how right Matthias is there.
Edit: The quotes belong to the url, but the forum software does not like them inside the url tags, and neither very much outside :(
|
|
Back to top |
|
|
DeveloperX 202192397
Joined: 04 May 2003 Posts: 1626 Location: Decatur, IL, USA
|
Posted: Tue Mar 03, 2009 4:02 pm Post subject: |
[quote] |
|
Hajo wrote: |
Edit: The quotes belong to the url, but the forum software does not like them inside the url tags, and neither very much outside :( |
You need to use HTML entity encoding
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/String.html#intern%28%29
About the StringId:
I looked through your code Mattias, and honestly, I don't fully understand the whole hashmap thing that you have going in Pixie. :S
I'm not going to worry too much about memory usage since its cheap these days and its highly unlikely that I will have enough strings in memory to be any issue. I'm also not worried about optimizations at this point. I'm making really basic games here and the systems that are being marketed today are more than 50 times powerful enough to handle anything I'll be throwing at it.
In response to Tenshi:
I see where you are going with that.
Its similar to what I'm doing now, except I don't create my instance on the heap. _________________ Principal Software Architect
Rambling Indie Games, LLC
See my professional portfolio
|
|
Back to top |
|
|
Mattias Gustavsson Mage
Joined: 10 Nov 2007 Posts: 457 Location: Royal Leamington Spa, UK
|
Posted: Tue Mar 03, 2009 4:34 pm Post subject: |
[quote] |
|
Well, my StringId class is a bit more complicated than needed, as it also functions as a HashTableKey.
But my point was more conceptual: it's better to use shared strings, for both performance and memory. The way I see it, is that it doesn't hurt to worry about the small things, because you never know when they'll come back and bite you. Like a game requiring 4 times as much memory as a normal PC has, and therefore using the swapfile like crazy :D _________________ www.mattiasgustavsson.com - My blog
www.rivtind.com - My Fantasy world and isometric RPG engine
www.pixieuniversity.com - Software 2D Game Engine
|
|
Back to top |
|
|
RedSlash Mage
Joined: 12 May 2005 Posts: 331
|
Posted: Tue Mar 03, 2009 5:15 pm Post subject: |
[quote] |
|
I know that GCC's STL uses copy-on-write optimizations on string, so in theory as long as you're taking advantage of this optimization (using consts properly, etc..), you should be reducing the effects of duplicate copies and comparisons. But I don't really know if it makes the difference, since I usually use const char *, and it seems to be consistant in behaviour.
|
|
Back to top |
|
|
Tenshi Everyone's Peachy Lil' Bitch
Joined: 31 May 2002 Posts: 386 Location: Newport News
|
Posted: Wed Mar 04, 2009 12:05 am Post subject: |
[quote] |
|
I know in my case theoretically it shouldn't be using much memory at all because there will be few strings in memory in the first place and the majority of the time the strings aren't even actually directly referenced (iterators used). The only time the strings are even checked is if a script I write needs to directly address one, and I went with Strings because it's much easier than trying to keep track of integers when writing a billion scripts anyway. _________________ - Jaeda
|
|
Back to top |
|
|