Problem with variation on the Singleton pattern

Discussion in 'C++' started by Eric, Feb 18, 2006.

  1. Eric

    Eric Guest

    I am implementing a variation on the Singleton design pattern, that
    allows up to 8 objects of a class to be instantiated, and returns a
    null pointer for anything more than 8.

    I am running into a compile problem with GNU g++.

    Here is the code:

    /******************** FILE sample.h ********************/

    #ifndef SAMPLE_H
    #define SAMPLE_H

    class Allow_8_Objects
    {
    public:

    // Destructor is public so that it can be executed by
    // "delete"ing the pointer to the object. Note that the
    // Contstructor is protected so it can't be executed
    // from the outside with "new" (one of the rules for
    // the Singleton design pattern).
    //
    ~Allow_8_Objects();

    static Allow_8_Objects* MakeInstance( void );
    // This method creates an object of this class, and
    // returns its pointer. Returns NULL if no more
    // objects can be made or some other error
    // happened.

    protected:

    Allow_8_Objects();
    // Protected constructor as part of the implementation
    // of a modified Singleton design pattern (modified to
    // allow 8 instances).

    private:

    static Allow_8_Objects* theInstance;
    // an instance of this class. Static
    // because it is used by MakeInstance(), which is
    // static. This pointer is what is returned by
    // MakeInstance().

    static int numInstances;
    // number of instances in existence. Cannot
    // exceed maxObjects. Note: static.
    };

    #endif // SAMPLE_H

    /**************** END OF FILE sample.h *****************/

    /*******************************************************/

    /******************* FILE sample.cpp *******************/

    #include "sample.h"

    static const int maxObjects = 8;
    // Maximum of 8 objects allowed per node

    int Allow_8_Objects::numInstances = 0;

    Allow_8_Objects::Allow_8_Objects()
    {
    }

    Allow_8_Objects::~Allow_8_Objects()
    {
    }

    /********** HERE IS THE METHOD WITH THE PROBLEM **********/

    // Make another object if not already at max.
    //
    Allow_8_Objects* Allow_8_Objects::MakeInstance( void )
    {
    theInstance = (Allow_8_Objects*)NULL;

    // If we already have the max number of objects, leave
    // the return pointer set to NULL, else make a new object
    // and get ready to return its pointer.
    //
    if ( numInstances < maxObjects )
    {
    theInstance = new Allow_8_Objects;
    }
    return theInstance;
    }

    /*************** END OF FILE sample.cpp ****************/

    Note that MakeInstance( ) is static, and theInstances and numInstances
    are both static. So, MakeInstance shouldn't have any trouble
    accessing theInstances and numInstances, right?

    What happens when I compile this is that the cimpiler complains about
    "undefined reference to Allow_8_Objects::theInstance" at lines 1, 7,
    and 11 of MakeInstance(). It can find and compile numInstances just
    fine (line 9 of MakeInstance()), just not theInstance.

    Any ideas?
     
    Eric, Feb 18, 2006
    #1
    1. Advertising

  2. On Sat, 18 Feb 2006 10:38:02 -0500, Eric
    <> wrote:

    >
    >I am implementing a variation on the Singleton design pattern, that
    >allows up to 8 objects of a class to be instantiated, and returns a
    >null pointer for anything more than 8.
    >
    >I am running into a compile problem with GNU g++.
    >
    >Here is the code:
    >
    >/******************** FILE sample.h ********************/
    >
    >#ifndef SAMPLE_H
    >#define SAMPLE_H
    >
    >class Allow_8_Objects
    >{
    >public:
    >
    > // Destructor is public so that it can be executed by
    > // "delete"ing the pointer to the object. Note that the
    > // Contstructor is protected so it can't be executed
    > // from the outside with "new" (one of the rules for
    > // the Singleton design pattern).
    > //
    > ~Allow_8_Objects();
    >
    > static Allow_8_Objects* MakeInstance( void );
    > // This method creates an object of this class, and
    > // returns its pointer. Returns NULL if no more
    > // objects can be made or some other error
    > // happened.
    >
    >protected:
    >
    > Allow_8_Objects();
    > // Protected constructor as part of the implementation
    > // of a modified Singleton design pattern (modified to
    > // allow 8 instances).
    >
    >private:
    >
    > static Allow_8_Objects* theInstance;
    > // an instance of this class. Static
    > // because it is used by MakeInstance(), which is
    > // static. This pointer is what is returned by
    > // MakeInstance().
    >
    > static int numInstances;
    > // number of instances in existence. Cannot
    > // exceed maxObjects. Note: static.
    >};
    >
    >#endif // SAMPLE_H
    >
    >/**************** END OF FILE sample.h *****************/
    >
    >/*******************************************************/
    >
    >/******************* FILE sample.cpp *******************/
    >
    >#include "sample.h"
    >
    >static const int maxObjects = 8;
    > // Maximum of 8 objects allowed per node
    >
    >int Allow_8_Objects::numInstances = 0;
    >
    >Allow_8_Objects::Allow_8_Objects()
    >{
    >}
    >
    >Allow_8_Objects::~Allow_8_Objects()
    >{
    >}
    >
    >/********** HERE IS THE METHOD WITH THE PROBLEM **********/
    >
    >// Make another object if not already at max.
    >//
    >Allow_8_Objects* Allow_8_Objects::MakeInstance( void )
    >{
    > theInstance = (Allow_8_Objects*)NULL;
    >
    > // If we already have the max number of objects, leave
    > // the return pointer set to NULL, else make a new object
    > // and get ready to return its pointer.
    > //
    > if ( numInstances < maxObjects )
    > {
    > theInstance = new Allow_8_Objects;
    > }
    > return theInstance;
    >}
    >
    >/*************** END OF FILE sample.cpp ****************/
    >
    >Note that MakeInstance( ) is static, and theInstances and numInstances
    >are both static. So, MakeInstance shouldn't have any trouble
    >accessing theInstances and numInstances, right?
    >
    >What happens when I compile this is that the cimpiler complains about
    >"undefined reference to Allow_8_Objects::theInstance" at lines 1, 7,
    >and 11 of MakeInstance(). It can find and compile numInstances just
    >fine (line 9 of MakeInstance()), just not theInstance.
    >
    >Any ideas?


    You are getting a linker error because you didn't initialize
    theInstance. It compiles just fine, at least on my compiler, but it
    won't link. Put this in your .cpp file:

    Allow_8_Objects *Allow_8_Objects::theInstance = 0;

    Also, you don't #include whatever header defines NULL (probably
    stddef.h??). But using 0 works just as well.

    Some other things to think about:

    (1) You have declared the default constructor protected, implying that
    other classes will eventually derive from this one. If you ever delete
    such a class through the base class pointer, you need to provide a
    virtual destructor. Otherwise, you get undefined behavior.

    (2) When someone deletes an instance of the class, what happens
    (should happen) to numInstances?

    (3) What about copying and assignment? Generally you wouldn't want to
    allow copying a singleton, but since you have more than one, perhaps
    it would make sense. If not, you should declare these private but
    don't implement them.

    (4) You'll need to think about synchronization issues in case these
    objects will be created in different threads.

    (5) Since you have a fixed ceiling of eight objects, I wonder if it
    wouldn't make more sense to create eight static objects up front and
    that way avoid the ensuing memory management problems? But we don't
    have enough information yet about what you are trying to do.

    --
    Bob Hairgrove
     
    Bob Hairgrove, Feb 18, 2006
    #2
    1. Advertising

  3. Eric

    Eric Guest

    On Sat, 18 Feb 2006 17:41:28 +0100, Bob Hairgrove
    <> wrote:

    >You are getting a linker error because you didn't initialize
    >theInstance. It compiles just fine, at least on my compiler, but it
    >won't link. Put this in your .cpp file:
    >
    >Allow_8_Objects *Allow_8_Objects::theInstance = 0;


    Good afternoon, Bob.

    Thanks, that did it. :)

    And thanks for your other items of advice. I will consider each and
    will probably implement most. I'm relatively new at C++, about 2
    years' experience over the last 4 years (though I have about 21 years'
    experience with C) and some of the more exotic features of the
    language like virtual destructors still leave me scratching my head a
    bit. But, I'm learning. :)

    >(2) When someone deletes an instance of the class, what happens
    >(should happen) to numInstances?


    It should (will) get set to zero, as will the pointer to the instance
    of the class.

    >(3) What about copying and assignment? Generally you wouldn't want to
    >allow copying a singleton, but since you have more than one, perhaps
    >it would make sense. If not, you should declare these private but
    >don't implement them.


    I don't think that I plan to copy them (if I understand correctly what
    you mean), but what do you mean by declaring these private (what are
    "these") but not implementing them?

    >(4) You'll need to think about synchronization issues in case these
    >objects will be created in different threads.


    Fortunately this is a single-threaded application so I'm pretty safe
    there.

    >(5) Since you have a fixed ceiling of eight objects, I wonder if it
    >wouldn't make more sense to create eight static objects up front and
    >that way avoid the ensuing memory management problems? But we don't
    >have enough information yet about what you are trying to do.


    The reason I don't do that is that not all 8 of them will necessarily
    get used, in fact most often only one will be used, occasionally two,
    rarely more than that, and if they don't get used I don't want them
    occupyingr memory unnecessarily.

    Thanks...

    Eric
     
    Eric, Feb 18, 2006
    #3
  4. On Sat, 18 Feb 2006 15:26:41 -0500, Eric
    <> wrote:

    >On Sat, 18 Feb 2006 17:41:28 +0100, Bob Hairgrove
    ><> wrote:
    >
    >>You are getting a linker error because you didn't initialize
    >>theInstance. It compiles just fine, at least on my compiler, but it
    >>won't link. Put this in your .cpp file:
    >>
    >>Allow_8_Objects *Allow_8_Objects::theInstance = 0;

    >
    >Good afternoon, Bob.
    >
    >Thanks, that did it. :)


    :)

    >And thanks for your other items of advice. I will consider each and
    >will probably implement most. I'm relatively new at C++, about 2
    >years' experience over the last 4 years (though I have about 21 years'
    >experience with C) and some of the more exotic features of the
    >language like virtual destructors still leave me scratching my head a
    >bit. But, I'm learning. :)
    >
    >>(2) When someone deletes an instance of the class, what happens
    >>(should happen) to numInstances?

    >
    >It should (will) get set to zero, as will the pointer to the instance
    >of the class.
    >
    >>(3) What about copying and assignment? Generally you wouldn't want to
    >>allow copying a singleton, but since you have more than one, perhaps
    >>it would make sense. If not, you should declare these private but
    >>don't implement them.

    >
    >I don't think that I plan to copy them (if I understand correctly what
    >you mean), but what do you mean by declaring these private (what are
    >"these") but not implementing them?


    If you don't declare them, the compiler will generate default versions
    of the copy constructor and the assignment operator for you.
    Unfortunately, there might not do what you want. E.g., if you allocate
    memory dynamically anywhere and have a pointer as member variable, you
    will want to make sure that the memory is actually copied and not just
    the pointer. Therefore, to ensure that objects are properly copied,
    you need to implement a copy constructor and assignment operator that
    do the right thing.

    However, if you wish to disallow copying and assignment, you can
    declare the copy constructor and the assignment operator as "private"
    and simply leave out any implementation or function body for these.
    That way, the compiler will generate an error when a client tries to
    copy or assign to one of the objects.

    >>(4) You'll need to think about synchronization issues in case these
    >>objects will be created in different threads.

    >
    >Fortunately this is a single-threaded application so I'm pretty safe
    >there.
    >
    >>(5) Since you have a fixed ceiling of eight objects, I wonder if it
    >>wouldn't make more sense to create eight static objects up front and
    >>that way avoid the ensuing memory management problems? But we don't
    >>have enough information yet about what you are trying to do.

    >
    >The reason I don't do that is that not all 8 of them will necessarily
    >get used, in fact most often only one will be used, occasionally two,
    >rarely more than that, and if they don't get used I don't want them
    >occupyingr memory unnecessarily.


    How did you come up with the magic number 8 in that case? Seems to me
    to be a bit arbitrary...

    --
    Bob Hairgrove
     
    Bob Hairgrove, Feb 18, 2006
    #4
  5. Eric

    Eric Guest

    On Sat, 18 Feb 2006 22:21:22 +0100, Bob Hairgrove
    <> wrote:

    >How did you come up with the magic number 8 in that case? Seems to me
    >to be a bit arbitrary...


    Mostly because the project engineer said "Allow for a maximum of 8"
    and I snapped to attention, rendered a brisk salute, and said "Yes,
    sir". :)
     
    Eric, Feb 19, 2006
    #5
  6. Eric

    Luke Meyers Guest

    Eric wrote:
    > On Sat, 18 Feb 2006 22:21:22 +0100, Bob Hairgrove
    > <> wrote:
    >
    > >How did you come up with the magic number 8 in that case? Seems to me
    > >to be a bit arbitrary...

    >
    > Mostly because the project engineer said "Allow for a maximum of 8"
    > and I snapped to attention, rendered a brisk salute, and said "Yes,
    > sir". :)


    Sure, but it's more fun like:

    template <size_t n>
    class allow_n_instances;

    :)

    Luke
     
    Luke Meyers, Feb 19, 2006
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Proton Projects - Moin

    Singleton - Whether Cloneable overrides Singleton

    Proton Projects - Moin, Mar 26, 2007, in forum: Java
    Replies:
    4
    Views:
    3,253
    Proton Projects - Moin
    Mar 27, 2007
  2. rahul
    Replies:
    2
    Views:
    344
    Flash Gordon
    Dec 1, 2009
  3. Wilhelm
    Replies:
    1
    Views:
    166
  4. Trans
    Replies:
    12
    Views:
    280
    Robert Klemme
    Sep 14, 2007
  5. Paul McMahon
    Replies:
    3
    Views:
    206
    David A. Black
    Jun 9, 2008
Loading...

Share This Page