1
static T& GetInstance()
{
    static T* instance = new T();
    return *instance;
}
static T& GetInstance()
{
    static T instance;
    return instance;
}

Is there any different in these two methods of GetInstance? (except that one will be allocated in heap, one in stack)

Which one is better practice?

Silver
  • 406
  • 2
  • 12
  • 1
    It's opinion based - but the second is the better option – Ted Lyngmo Feb 15 '22 at 03:02
  • 2
    I cant think of a case where I would use the first version. – Borgleader Feb 15 '22 at 03:03
  • in first case you can have memory leak if caller forget to delete instance – Iłya Bursov Feb 15 '22 at 03:04
  • 1
    @273K How? The construction of `instance` in the second example is thread safe by definition. What happens after that obeys by the same rules as in any other multithreaded program. – Ted Lyngmo Feb 15 '22 at 03:36
  • @IłyaBursov I do not want it to be deleted, and also second version will never be deleted too, since the `instance` do not end its lifetime – Silver Feb 15 '22 at 03:50
  • @Silver _"I do not want it to be deleted_" - It will be anyway if you've created a program with defined behavior and no memory leaks. If you like that idea, you only have to decide _when_ and _how_ it'll be deleted. The second point is just wrong: _"since the `instance` do not end its lifetime"_ - it does. – Ted Lyngmo Feb 15 '22 at 04:00
  • 1
    Note sometimes you don't want the singleton to be destroyed. – user4581301 Feb 15 '22 at 04:11
  • @TedLyngmo enlight me how the `instance` end its lifetime. In my view, `static` will ensure there is at least on reference to `instance`, so it won't end its lifetime. – Silver Feb 15 '22 at 04:30
  • @Silver In the second version the `T` object will be destroyed (its lifetime ended) after `main` exits. In the first version it wont. – user17732522 Feb 15 '22 at 04:32
  • @user17732522 after main exits, the kernel will retrieve its memory, so `instance` will also be delete (althought destructor will not called) – Silver Feb 15 '22 at 04:34
  • @Silver _"In my view, `static` will ensure there is at least on reference to instance, so it won't end its lifetime"_ - why do you think that? – Ted Lyngmo Feb 15 '22 at 04:36
  • @TedLyngmo If I'm not wrong, `static` will tell the compiler to pre-allocate a static memory for the object to station in. And `instance` will keep the object alive. I do not want my singleton to be destruct during runtime, so if the `instance` run out of its lifetime before main exits or exception threw, it will be bad. – Silver Feb 15 '22 at 04:39
  • 1
    @Silver The point is that the program itself will end the lifetime of the `T` object in the second version at some point after `main` exits, while in the first one it doesn't. What the operating system does it outside the scope of the program behavior. Whether and when the destructor is called is the only relevant thing to the program behavior and that differs between the two versions. – user17732522 Feb 15 '22 at 04:40
  • @Silver C++ is _imperfect_ in that it reuses reserved words for ... things. `auto` springs to mind ... – Ted Lyngmo Feb 15 '22 at 04:42
  • @user17732522 I just do not want my singleton stay alive during runtime (until main exits or exception threw), so if the second version ensure that, that will be great (I do concern about Ted saying that `instance` may end its lifetime during runtime) – Silver Feb 15 '22 at 04:52
  • @Silver After `main` exits, but before the program completely ends, is still "during runtime" and the difference is significant. For example if you have other static storage duration objects, whose destructor relies on this local static to still be alive when it runs, there may be issues. – user17732522 Feb 15 '22 at 05:03
  • https://godbolt.org/z/WErPf99ej – Marek R Feb 16 '22 at 17:55

3 Answers3

1

I will try to summarize all the comments
So there is many differences between 2 version.

static T* version static T version
memory location heap stack
thread safe yes yes
null possible? no, if new failed, there will be an exception throw no
destructor call on main exit no yes
performance cost of heap allocation low cost of performance
when the memory is freed? after the program end and kernel take back its resource at main exit
when should we use If you need a lazy allocation for memory optimization The memory is allocated at compile time. So use this when you are sure that the singleton has a use in the code

So by the table, static T version seem to be superior in many way.

Silver
  • 406
  • 2
  • 12
0

The main difference is that in the first implementation, you have no valid way to delete the T* instance, resulting a memory leak.

On the contrary, second one will be properly deleted when the program ends : What is the lifetime of a static variable in a C++ function?

Therefore, I suggest the latter practice when you progrm the Singleton in general.

K.R.Park
  • 1,015
  • 1
  • 4
  • 18
  • In defense of the first, it is protection against something you shouldn't want to do in the first place. With the singleton you guarantee that the object will be created on time, every time and avoid the Static Initialization Order Fiasco. BUT! You've reduced your control over when the instance will be destroyed. If it is created late, it will be destroyed early. Perhaps too early. In the first option, there is no destruction and the instance will be available. I reiterate: both options leave boobytraps, and you don't want to do this carelessly. – user4581301 Feb 15 '22 at 16:29
0

Yes, there is a difference. In the first function, a pointer is stored in the static area and the T object is stored on the heap (dynamic memory). In the second, the T object is stored in the static area.

The second function is better by pretty much any metric (with one extremely rare exception I mention below). There are two reasons for this:

First, the first function allocates a T object behind a pointer but returns the dereferenced value at that pointer. That means that you have (sort of) lost your handle on that piece of memory so you can never deallocate it. It is declared as static so at least it won't allocate new memory each time the function is called, but it is still not a great idea.

Second, heap allocations are expensive in terms of performance (when compared to storing something in the static area or on the stack). It is generally good practice to avoid heap allocations unless you need heap allocations.

The only case I can think of where you might want to use the first function (assuming it is revised to not leak memory) is if a T object is too large to fit in the static area. It would have to be really large indeed, but it is a possible scenario.

tedtanner
  • 577
  • 6
  • 19
  • The details you're giving are not mandated by the standard, but they seem plausible. "stack" and "heap" are implementation details. – Ted Lyngmo Feb 15 '22 at 04:49
  • You are correct. All major C++ compilers (and pretty much all other C++ compilers as well) have a concept of a stack and a heap, so it is helpful to think in terms of a stack and a heap. The term "dynamic memory" could be substituted for "heap" if you want to be more correct to the standard. – tedtanner Feb 15 '22 at 04:55
  • 1
    Thing is, dynamic memory describes the concept much better than heap does. For one thing it tells you that the lifetime is dynamic. Heap is embedded in the language to the point that folks who know programming know what you're talking about when you say heap. Other folk could think you're discussing the great wise elder of Fraggle Rock,, though. – user4581301 Feb 15 '22 at 18:22
  • I added the term “dynamic memory” to my answer – tedtanner Feb 16 '22 at 17:29