0

I have the following code that implements a basic Meyers singletone:

#ifndef _cConfigFile_HH
#define _cConfigFile_HH

class cConfigFile {
public:
  static cConfigFile& getInstance() {
    static cConfigFile instance;
    return instance;
  };
private:
  cConfigFile();
};

#endif

My compiler doesn't allow me to compile this, giving the following error:

/include/cConfigFile.hh:7: undefined reference to `cConfigFile::cConfigFile()'

From the error I understand that I need to declare "instance" in a .cpp file, but am unable to declare cConfigFile::instance because the compiler says:

‘cConfigFile cConfigFile::instance’ is not a static

What am I doing wrong?? I'm lost here..

Dan Breslau
  • 11,472
  • 2
  • 35
  • 44
Markoff Chaney
  • 313
  • 1
  • 4
  • 7
  • 1
    Why is there a `-` in front of the `static` keyword? – James McNellis Jan 26 '11 at 18:31
  • Sorry, I pasted it from emacs where a minor mode formats the source code that way. Edited. – Markoff Chaney Jan 26 '11 at 18:32
  • 4
    Clearly this demonstrates that vi is superior ;-) – James McNellis Jan 26 '11 at 18:46
  • 1
    Please don't use singleton unless you absolutely positively have to and there is no other alternative you can think of. It's basically a global variable, with all the attendant disadvantages, and the added disadvantage of a policy decision (There can be only one!) implemented in a way that's very difficult to fix later. – Omnifarious Jan 26 '11 at 18:48
  • 1
    @Omnifarious: There is nothing wrong with global variables (and thus, Singletons as well) in and of themselves. It is really how they are being used/misused that causes problems. Suggesting someone avoid a singleton because it is a "global variable" is not a reason. Without knowing what he is doing, you cannot make that recommendation with certainty. – Zac Howland Jan 26 '11 at 18:54
  • 1
    [On vim vs. emacs](http://en.tiraecol.net/modules/comic/comic.php?content_id=2&mode=flat&order=0) -- The translation into english is quite bad, but understandable (Original in [Spanish](http://www.tiraecol.net/modules/comic/comic.php?content_id=3&mode=flat&order=0) ). – David Rodríguez - dribeas Jan 26 '11 at 18:58
  • @Zac Howland: I can make that recommendation with certainty. Global variables reduce testability, make dependencies between different sections of code unclear, and make code less secure because they basically grant every piece of code the ability to access the global variable regardless of whether or not that bit of code needs it. This violates the important security principle of least authority. They are just as bad a programming practice as goto. I can say with confidence that 99.99% of the situations in which they're used, they shouldn't be. – Omnifarious Jan 26 '11 at 19:01
  • 1
    @Omnifarious Well this singleton is to store a global configuration file and some methods to work with that global configuration file (like re-loading etc). I only see two alternatives and none seems better: 1. a global variable (like a struct) and functions to work with it (the "C" way) and 2. Using a single object and passing it around with pointers (but besides the fact that it's ugly, I have no guarantee that more objects could be created and given the fact that there will be methods that will involve i/o, nasty stuff could happen)... I'm really open to advices, if anyone has one.. – Markoff Chaney Jan 26 '11 at 19:09
  • @Markoff Chaney - I'm making this an answer because it's too long for a comment. – Omnifarious Jan 26 '11 at 19:13
  • @Markoff Chaney - There, I've given you an alternative that should solve your problem in an answer. – Omnifarious Jan 26 '11 at 19:38
  • Does anyone have experience where using a Singleton to manage configuration settings bit them in the ass, or does it just sound smart to rag on Singletons? – JohnMcG Jan 27 '11 at 14:28

4 Answers4

11

You forgot to implement your constructor.

Edward Strange
  • 40,307
  • 7
  • 73
  • 125
-1

The first error message means that you're missing the constructor for the instance.

As for the second: It would be a really good idea to include the .cpp code where you tried to define the instance. But it sounds like you tried to define the instance variable as a class static, which you're not supposed to do.

To instantiate the instance in a .cpp, you want to have something like this in your .hh file:

class cConfigFile {
public:
  static cConfigFile& getInstance();
private:
  cConfigFile() {} // Note: define the constructor -- this is probably not enough!
};

And this in your .cpp file:

cConfigFile& cConfigFile::getInstance()
{
    // Define the singleton as a local static
    static cConfigFile instance;

    return instance;
}

NOTE: You really want to define the getInstance method in a .cpp file, not as an inline function. Defining it as inline will give you one instance of instance for every .cpp file in which the header is used. That defeats the purpose of trying to make it a singleton!

Dan Breslau
  • 11,472
  • 2
  • 35
  • 44
  • That's a great advice. Point well taken. Thanks! – Markoff Chaney Jan 26 '11 at 18:56
  • 1
    The last point is incorrect. To C++03 7.1.2/4: "A static local variable in an extern inline function always refers to the same object." The function in the OP's post is extern because it is a static member function and it is inline because it is defined inside of the class definition. – James McNellis Jan 26 '11 at 20:00
  • @James: Thanks; I stand corrected. I think I remember this being an issue with older versions of C++ (particularly across shared library boundaries), but I can't find a reference to back this up. – Dan Breslau Jan 26 '11 at 20:21
  • Well, if you're exporting a class from a library, then yes, you do have to be careful. But in that case, you generally want to define all of the functionality in a source file to guarantee that none of it is inlined. – James McNellis Jan 26 '11 at 22:09
  • @James: Your reply seems to do a 180-degree turn, and say that inline functions should never be used. I don't think that's what you meant, but I'm not sure what else you were getting at. To clarify my own comment, I was referring to cases where 2 or more linked units (shared libraries, DLLs, etc.) *internally* use a header file which defines an inline accessor for a singleton -- in other words, they're not themselves exposing the functionality of that header file. – Dan Breslau Jan 26 '11 at 22:54
-2

You need to initialize the static instance at the bottom of the header file:

cConfigFile cConfigFile::instance;

And you need to take the declaration of the static instance outside of the getInstance() function.

class cConfigFile{
public:
  static cConfigFile instance;   //declare

  cConfigFile & getInstance(){

    return instance;
  }
private:
  cConfigFile(){}
};

cConfigFile cConfigFile::instance();  //initialize
J T
  • 4,946
  • 5
  • 28
  • 38
  • 3
    Not so -- the real "trick" of the Meyers singleton is that the static object is at the *function* level instead of the class level, specifically to avoid having to do this. If you did have to define an instance, you'd need to do it in a .cpp file, *not* the header, or you end up with multiple definitions if include the header in more than one other source file. – Jerry Coffin Jan 26 '11 at 18:40
-3

This isn't exactly an answer, just a response to a comment that's too long for another comment, and it is relevant to this question.

Please don't use Singleton. Your stated reason for doing so is that you will be using it to store configuration information, and that configuration information needs to be accessible from anywhere in the program.

This is a reason (though, IMHO, not necessarily a great one) for a global variable, but not a reason for a Singleton. What harm is there in more than one object that stores the configuration existing? If all users used a global variable to access it, they would all use the same one. Why is it helpful to forcibly constrain the number of instances to one?

Secondly, what happens in the future when you need to temporarily add some configuration options? Say somehow your program needs to sort of run itself as a sub-program or something with slightly different configuration information, then restore the original configuration? Or maybe you need to frob the configuration in a few different ways for tests and then restore it to its original state? With a Singleton and a global variable this becomes very tricky. But if you used something more flexible, it's pretty trivial.

Now personally, I think passing around the configuration options to all the things that need them in an explicit fashion is not necessarily a bad way to go. But if you think that's intolerable, here's an alternative:

template <typename T>
class DynamicallyScoped {
 public:
   explicit DynamicallyScoped(T &stackinstance) : oldinstance_(0) {
      oldinstance_ = S_curinstance;
      S_curinstance = &stackinstance;
   }
   ~DynamicallyScoped() {
      S_curinstance = oldinstance_;
      oldinstance_ = 0;
   }
   static T *curInstance() { return S_curinstance; }

 private:
   static T *S_curinstance;
   T *oldinstance_;

   // Made private and left undefined on purpose.
   DynamicallyScoped(const DynamicallyScoped &b);
   const DynamicallyScoped &operator =(const DynamicallyScoped &b);
};

This allows you to replace the current instance for a scope and have it automatically restored when that scope goes away. And it also allows you to say DynamicallyScoped<Foo>::curInstance()->get_something(); anywhere in your program, except in the constructors for static or global objects, and expect to get something useful.

It's a doodle, and probably useful in this form. But I can imagine ways in which it might be better. For example, with some modification you could have several dynamically scoped variables of the same type.

Example usage:

#include <iostream>

template <>
int *DynamicallyScoped<int>::S_curinstance = 0;

extern void doSomething();
extern void doSomethingElse();
extern void printTheInt();

int main(int argc, char *argv[])
{
    int x = 5;
    DynamicallyScoped<int> theInt(x);

    printTheInt();
    doSomething();
    doSomethingElse();
}

void doSomething()
{
    printTheInt();
}

void doSomethingElse()
{
    int newint = 6;
    DynamicallyScoped<int> subint(newint);
    doSomething();
}

void printTheInt()
{
    ::std::cout << "_The_ integer's value is: "
                << *DynamicallyScoped<int>::curInstance() << '\n';
}

As for the worry that more instances of your 'global config file' object could be created, don't hardcode the filename. Construct the object in main as a stack variable and give it the filename as an argument. Then there's no problem if other parts of the code create instances of the config file object unless they also give the name of the global configuration file. And if they do that, they deserve what they get.

Omnifarious
  • 54,333
  • 19
  • 131
  • 194
  • This is a good idea, and elegant. And yet, to your question, "what happens in the future when you need to temporarily add some configuration options?...With a Singleton and a global variable this becomes very tricky. But if you used something more flexible, it's pretty trivial." I can't see anything that prevents the OP from reimplementing `cConfigFile::getInstance()` to use `DynamicallyScoped::curInstance()->get_something()`. Premature elegance is not a virtue. – Dan Breslau Jan 26 '11 at 20:00
  • Thanks for taking the time to answer me so thoroughly. I don't understand why you have been downvoted. I must take some time to get my mind wrapped around your code, as I don't have that much experience with templates. Will come back later or start a new question after. Thanks again! – Markoff Chaney Jan 26 '11 at 20:45
  • @Markoff Chaney - I think I'm being marked down for my strong and unyielding stance that Singletons are a bad design decision. – Omnifarious Jan 28 '11 at 16:35