Thread: making a class only get constructed once

  1. #1
    Hail to the king, baby. Akkernight's Avatar
    Join Date
    Oct 2008
    Location
    Faroe Islands
    Posts
    717

    making a class only get constructed once

    hello.

    I'm trying to make a CWorld class that can only be constructed once, now Elysia told me the approach yesterday, still I forgot all the details so I've been mindless hacking for sometime, with only help from intellisense and some from cprogramming.com, still I ain't getting it right...

    Code:
    class CWorld
    {
    private:
    	hgeVector m_hVec_ScreenSize;
    
    	float m_Gravity;
    
    	boost::array<std::string, 1> m_str_mapNames;
    	void SetMapNames();
    
    	CWorld(const float gravity_);
    
    public:
    
    	hgePolygonMap* m_map;
    
    	friend class CWorld_Fac;
    
    	// HGE needed functions e.g. the creation of the world...
    	inline void SetStates();
    	static bool FrameFunc();
    	static bool RenderFunc();
    
    };
    
    class CWorld_Fac {
    
    public:
    
    	CWorld_Fac::CWorld_Fac(const float gravity_) {
    
    		static CWorld world_(gravity_);
    	}
    };
    Those are the classes I have, now I'm supposed to be able to create many CWorld_Fac classes, still it will always lead to the same CWorld class, since it's static, also I have this code in main()
    Code:
    world = new CWorld_Fac(0.5f);
    now this should be having the right info, and thus making CWorld get the right info first time...
    here is the call that fails
    Code:
    CWorld_Fac m_world;
    
    // this fails
    CCharacter(std::string entClass_) : CEntity(HEL_MIDDLE2, false), m_world(0) { m_world.m_map->RegisterEntityClass(entClass_, this); }
    now here I set m_world argument to 0, this shouldn't change anything since the CWorld constructor was static in CWorld_fac, right?

    Hope I was able to explain correctly, and thanks in advance!
    Currently research OpenGL

  2. #2
    Registered User
    Join Date
    Oct 2008
    Posts
    1,262
    For the record, this pattern is called a singleton. Makes google easier

    You should create a class with three private functions, that need not have a body, only a definition:
    - The copy constructor
    - The operator= with as argument the object itself
    - The constructor (ok, this should have a body)

    Then, a single, static member function, eg. called getInstance, which returns a reference to the object itself. Then do something similar to this:
    Code:
    class Singleton {
    public:
      static Singleton &getInstance();
    };
    
    Singleton &Singleton::getInstance()
    {
      static Singleton object;
      return object;
    }
    The object will be constructed once. To get a reference to the object, use Singleton::getInstance(). You can use it directly, eg:
    Singleton::getInstance().doSomething();

  3. #3
    Hail to the king, baby. Akkernight's Avatar
    Join Date
    Oct 2008
    Location
    Faroe Islands
    Posts
    717
    Well, I just got information that what I'm trying to do has already been done -.-
    We're using a SDK from another guy, hence we don't know ALL the code :S
    Currently research OpenGL

  4. #4
    The larch
    Join Date
    May 2006
    Posts
    3,573
    I don't see a reason why World should be constructed just once (in a game, why couldn't there be many worlds?).

    If you want one instance, don't create more.

    Singleton is often considered an antipattern: it basically encourages you to use global state while thinking what you are doing is OOP.

    ------

    Perhaps you could add a static counter to the class that you increment in the constructor and assert or throw if the counter gets above 1?
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  5. #5
    Hail to the king, baby. Akkernight's Avatar
    Join Date
    Oct 2008
    Location
    Faroe Islands
    Posts
    717
    we agreed on only one world, and it holds gravity and such, also for other classes to use it, they have to construct it again or pass it through argument (which I don't want)
    Currently research OpenGL

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Akkernight
    pass it through argument (which I don't want)
    Why not? After all, although you may decide up front that you only want one world, if you keep your design reusable then maybe even if the requirements change later it would not be such a hassle to accommodate the changes.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    My solution to this is an object factory:
    Code:
    #ifndef OBJFACTORY_174815_H
    #define OBJFACTORY_174815_H
    
    template<typename T>
    class ObjFactory
    {
    public:
    	static T* Create()
    	{
    		assert(m_Instances == 0); // Allow only one instance of the object
    		if (m_Instances >= 1)
    			return NULL;
    		T* p = new T;
    		m_Instances++;
    		return p;
    	}
    
    private:
    	static int m_Instances;
    };
    
    #endif // OBJFACTORY_174815_H
    No singleton, no global and will allow the construction of only one object.
    Of course, the object being constructed needs a private constructor and make the object factory a friend.
    Last edited by Elysia; 04-13-2009 at 12:08 PM. Reason: Updated code!
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  8. #8
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    Yikes!

    So... you just terminate the program if you accidentally try to create a second one? And only in debug mode? But you allow more than one to be created in release mode?

    I think you need a new solution...

    Anyway, as anon said, if you only want one instance, don't create more than one.

    If you are only using the singleton pattern to avoid passing parameters... you fail.

    Soma

  9. #9
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    It's not to hinder; it's to catch mistakes.
    I could easily make it throw an exception, but at this point, I didn't think it was necessary.
    Or is it necessary in your opinion? Or perhaps simply returning NULL?
    Well, returning NULL doesn't hurt, so let's add it as a good measure.

    Meh. Not such a good design, since you can't rely on it returning NULL, it at least it catches your mistakes in Debug mode.
    Last edited by Elysia; 04-13-2009 at 12:13 PM.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  10. #10
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    None of the above...

    I was just making a few points:

    1): You should never use `assert' for checks that should always be performed.
    2): An object capable of being instantiated more than once is never a singleton--regardless of what people might like to call it.
    3): "Crash and Burn" is not a good strategy to handle events very likely to occur in the course of normal program execution.

    Soma

  11. #11
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by phantomotap View Post
    None of the above...

    I was just making a few points:

    1): You should never use `assert' for checks that should always be performed.
    2): An object capable of being instantiated more than once is never a singleton--regardless of what people might like to call it.
    3): "Crash and Burn" is not a good strategy to handle events very likely to occur in the course of normal program execution.

    Soma
    1) Very true, but that is not the main purpose.
    2) o_O I wouldn't call this a singleton at all anyway.
    3) Absolutely, but this design was meant to catch mistakes in trying to instantiate two or more objects of the same type, not hinder them. Therefore, to the first point, I used an assert and not an if to check if there are 2 or more instantiations.

    I could make one that checks each time you make one and fail if it already has made one... But I didn't feel it necessary. Is it necessary? I can't say.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  12. #12
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    Quote Originally Posted by Elysia View Post
    It's not to hinder; it's to catch mistakes.
    I could easily make it throw an exception, but at this point, I didn't think it was necessary.
    Or is it necessary in your opinion? Or perhaps simply returning NULL?
    Well, returning NULL doesn't hurt, so let's add it as a good measure.

    Meh. Not such a good design, since you can't rely on it returning NULL, it at least it catches your mistakes in Debug mode.
    I wouldn't throw an exception, since you could leak the memory of the allowed instance if you unwind the stack too far. In my opinion, I think the best idea is to just make one instance, rather than rely on some boilerplate or your idea that returns zombie objects when you don't have the presence of mind to restrict yourself. Just check the code.

    Making the class noncopyable (isn't there something like Boost::noncopyable?) takes care of the concern of the instance being used as a function argument to a large extent.
    Last edited by whiteflags; 04-13-2009 at 01:13 PM.

  13. #13
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Then we're back to the first design - an object factory which can catch your mistakes and save you time.
    Your suggestion about non-copyable is good too.
    Yeah, boost has a noncopyable class that you can inherit from to disable copying.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  14. #14
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Show me one coder who has accidentally created more instances of something as big as CWorld than he wanted and didn't even notice the code was malfunctioning and needed correcting.

    It's really all about making an instance global in this case.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  15. #15
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    I know of one coder whose name I'm not about to give out, who actually created another instance of a singleton.
    I had to make the constructor private and use friends to catch that mistake.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Getting an error with OpenGL: collect2: ld returned 1 exit status
    By Lorgon Jortle in forum C++ Programming
    Replies: 6
    Last Post: 05-08-2009, 08:18 PM
  2. Screwy Linker Error - VC2005
    By Tonto in forum C++ Programming
    Replies: 5
    Last Post: 06-19-2007, 02:39 PM
  3. Creating a database
    By Shamino in forum Game Programming
    Replies: 19
    Last Post: 06-10-2007, 01:09 PM
  4. structure vs class
    By sana in forum C++ Programming
    Replies: 13
    Last Post: 12-02-2002, 07:18 AM