17

So, classic simple Singleton realization is following:

class Singleton
{
private:
    static Singleton* singleton;
    Singleton() {}
public:
    static Singleton* getInstance();        
};

cpp-file:

Singleton* Singleton::singleton = 0;

Singleton* Singleton::getInstance()
{
    if (!singleton)
    {
        singleton = new Singleton;
    }

    return singleton;
}

I see memory leak here - 'cos there is no delete for the new. But in C++ there isn't static destructor, so we just don't care about this memory leak?

Mat
  • 202,337
  • 40
  • 393
  • 406
Hate
  • 1,185
  • 3
  • 12
  • 24
  • 4
    Singletons are expected to be useful for the whole life of the program. – zneak Apr 01 '12 at 20:45
  • See [C++ Singleton design pattern](http://stackoverflow.com/questions/1008019/c-singleton-design-pattern) (or just search for singleton on SO, you will find a lot of info) – Jesse Good Apr 01 '12 at 20:46
  • This looks as rewritten Singleton implementation in C#: http://msdn.microsoft.com/en-us/library/ff650316.aspx But in C# "new" does not require "delete". – SChepurin Apr 01 '12 at 21:43
  • @SChepurin This example is from GoF book – Hate Apr 01 '12 at 22:22
  • @Hate.Nothing's perfect. There is a lot to be discussed about Singleton's deletion "How does a Singleton ever get deleted?": http://sourcemaking.com/design_patterns/to_kill_a_singleton – SChepurin Apr 01 '12 at 22:48

3 Answers3

34

A memory leak is more than just an allocation with no matching free. It's when you have memory that could be reclaimed because the object is no longer in use, but which doesn't ever actually get freed. In fact, many memory leaks are cases where there is code in the program to deallocate memory, but for whatever reason it doesn't get called (for example, a reference cycle). There's a lot of research on how to detect these sorts of leaks; this paper is an excellent example of one such tool.

In the case of a singleton, we don't have a leak because that singleton exists throughout the program. Its lifetime is never intended to end, and so the memory not getting reclaimed isn't a problem.

That said, the code you have above is not how most people would implement a singleton. The canonical C++ implementation would be something like this:

class Singleton
{
private:
    /* No instantiation. */
    Singleton() {}

    /* Explicitly disallow copying. */ 
    Singleton(const Singleton&) = delete;
    Singleton& operator= (const Singleton&) = delete;

    /* In C++03, the above would be written as
     *
     *    Singleton(const Singleton&);
     *    Singleton& operator= (const Singleton&);
     * 
     * and you'd just leave the methods unimplemented.
     */
public:
    static Singleton& getInstance();        
};

.cpp file:

Singleton& Singleton::getInstance() {
    /* Have a static local variable representing the unique instance.  Since
     * it's static, there is only one instance of this variable.  It's also only
     * initialized when getInstance is called.
     */
    static Singleton theInstance;
    return theInstance;
}

Now there's no dynamic allocation at all - the memory is allocated by the compiler and probably resides in the code or data segment rather than in the heap. Also note that you have to explicitly disallow copying, or otherwise you could end up with many clones of the singleton.

The other advantage of this is that C++ guarantees that at program exit (assuming the program terminates normally), the destructor for theInstance will indeed fire at the end of the program. You can thus define a destructor with all the cleanup code you need.

Hope this helps!

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • what is = delete; and aren't you declaring new static theInstance every time you call the getInstance()? – Hate Apr 01 '12 at 20:52
  • 1
    @Hate- `= delete;` is a new C++11 syntax for explicitly marking that a function does not exist and cannot be called. In C++03, you'd just declare these functions but not implement them. Also, the reason you don't get a new copy of the instance each time is that the local variable is marked `static`, which means that only one copy of this variable exists and it persists across function invocations. Does that answer your question? Or is there something else I can clarify? – templatetypedef Apr 01 '12 at 20:53
  • I see that static Singleton theInstance; create static variable, and I know that static vars exits all the time program run. But when you call this function for second time, won't it be willing on creating new static variable theInstance and it will be no redefinition error? – Hate Apr 01 '12 at 20:57
  • 1
    @Hate- Nope. Static local variables are similar to static global variables in that only one copy actually exists. If you call the function multiple times, it always refers to the same static local variable. See http://stackoverflow.com/questions/246564/what-is-the-lifetime-of-a-static-variable-in-a-c-function for more details. – templatetypedef Apr 01 '12 at 20:58
  • when I write in main class Test {}; static Test test; static Test test; it gets me an error of test redefinition.. – Hate Apr 01 '12 at 21:03
  • That's correct - there's a difference between creating two different static global variables and having just one static local variable invoked twice. One is at a syntactic level and is illegal, while the other is a consequence of the runtime. – templatetypedef Apr 01 '12 at 21:05
  • I don't get why it happens so, why there is no redefinition error when it's static Singleton theInstance; in function that is called many times and it is an error when this line is several time in function that is called once.. – Hate Apr 01 '12 at 21:13
  • A redefinition error is a *syntactic* issue - you cannot declare the same variable twice. There is no redefinition in this case because there is just one definition. Calling a function with a static variable does not constitute a definition. Try writing this code for yourself to see what I mean - it should take about five minutes and will hopefully clear up the distinction. – templatetypedef Apr 01 '12 at 21:14
  • I wrote it by myself, still it isn't all clear to me.. I always thought that such line is a definition and can be only one in program.. – Hate Apr 01 '12 at 21:22
  • @templatetypedef - this sort of thinking makes it difficult to detect unwanted leaks because the "who cares" leaks create so much noise when running a program under tools with instrumentation. – jww Feb 19 '14 at 17:40
  • @Hate: 1. Your function (getInstance) is called: theInstance is initialized, to 0 in this case. 2. Your function is called again: When we pass the "static Singleton theInstance;" line, it is not a new definition. It is the exact same definition we passed before. Definition and initialization of statics happens only once. You can consider the line skipped. This is why statics are different from locals. All references to a static variable in the same scope refer to a single place in memory. You can not "redefine" any existing variable. Local variables refer to different memory per call. – Larry Feb 14 '19 at 15:51
4

Why you should avoid such code, when there is no matching delete for new

While there is no actual memory leak (in most modern operating systems), worse thing is that your Singleton destructor doesn't get called. And if you acquire some resources, they propbably would leak.

What can be done here

Use smart pointer to store instance, consider std::unique_ptr (with C++11) or boost::auto_ptr

Community
  • 1
  • 1
Lol4t0
  • 12,444
  • 4
  • 29
  • 65
  • 1
    @Lol4t0- The version in my code is also lazily initialized; `static` local variables are only initialized when the function containing them is first called. – templatetypedef Apr 01 '12 at 20:59
  • @templatetypedef, you defined it inside function, ok then. – Lol4t0 Apr 01 '12 at 21:05
  • @Lol4t0: You and templatetypedef gave two contradicting statements: you say that the Singleton destructor does not get called, whilst they say that the destructor gets fired when the program is finished. Since this is exactly what I came here to find out, would you mind confirming or denying your statement? – Larry Feb 14 '19 at 15:19
  • 1
    @Larry: it depends on Singleton implementation. The implementation in the body of the question does not fire destructior, but templatetypedef's implementation does. – Lol4t0 Feb 17 '19 at 21:02
  • @Lol4t0 Thank you! So it seems dynamic memory is not destroyed, only deallocated. – Larry Feb 19 '19 at 19:30
0

When a variable local to a function is declared "static", it means that it isn't allocated on the stack - and that its value persists from one call to the next.

user888379
  • 1,343
  • 12
  • 30