0

I'm studying C++. To practice, I tried to implement a very simple singleton class, but I can't understand why this causes an error.

When I return a reference to it (which I think I should use it like that), like static unique_ptr<Singleton>& getInstance(), it is accepted.

So, what's wrong here?

class Singleton
{
private:
    static unique_ptr<Singleton> obj;
    Singleton()
    {
        cout << "it's created!!\n";
    }

public:
    ~Singleton()
    {
        cout << "it's desctructed!!\n";
    }
    static unique_ptr<Singleton> getInstance()
    {
        if (obj.get() == nullptr)
            obj.reset(new Singleton());
        return obj;
    }
};
unique_ptr<Singleton> Singleton::obj{nullptr};


int main(){
  
  unique_ptr<Singleton> ss = Singleton::getInstance();
  return 0
}
/home/rt7/Desktop/ccProjects/cppTutorial/main.cc: In static member function ‘static std::unique_ptr<Singleton> Singleton::getInstance()’:
/home/rt7/Desktop/ccProjects/cppTutorial/main.cc:25:16: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Singleton; _Dp = std::default_delete<Singleton>]’
   25 |         return obj;
      |                ^~~
In file included from /usr/include/c++/11/bits/locale_conv.h:41,
                 from /usr/include/c++/11/locale:43,
                 from /usr/include/c++/11/iomanip:43,
                 from /usr/include/x86_64-linux-gnu/c++/11/bits/stdc++.h:72,
                 from /home/rt7/Desktop/ccProjects/cppTutorial/main.cc:1:
/usr/include/c++/11/bits/unique_ptr.h:468:7: note: declared here
  468 |       unique_ptr(const unique_ptr&) = delete;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Osman
  • 66
  • 1
  • 8
  • 3
    The first word in unique_ptr is **unique**. It is supposed to fail. You are trying to create 2 not so unique ptrs to the same object. – Avi Berger Sep 14 '22 at 19:39
  • 1
    The fact that you are returning, by copy, a unique_ptr? How can the unique ownership be maintained if the pointer were copyable? – StoryTeller - Unslander Monica Sep 14 '22 at 19:40
  • i see now, so what's the best practice would be here? returning referance of it seems more appropriate than returning as move(obj) to the caller? – Osman Sep 14 '22 at 19:42
  • 2
    It would. But I suggest you dispense with doing the rest of the work the hard way. A [Meyers singleton](https://stackoverflow.com/q/17712001/817643) will give you the same interface, with thread safety, but without a hassle. – StoryTeller - Unslander Monica Sep 14 '22 at 19:44
  • You definitely don't want to `move(obj)`. That would transfer ownership out of the singleton and leave it "empty". On the next `getInstance` call `if (obj.get() == nullptr)` will enter the body and create another instance. Whups. – user4581301 Sep 14 '22 at 19:54
  • @user4581301 i set it to nullptr frist, so it'll act like lazy singleton but other than that i see the point of not moveing obj so returning referance of it would make sense to me as well. – Osman Sep 14 '22 at 19:58
  • https://stackoverflow.com/q/1008019/14065 – Martin York Sep 14 '22 at 21:23

1 Answers1

2

The singleton is the object owner. Usually a raw pointer is returned if the ownership is not transfered.

static Singleton* getInstance()
{
    if (!obj)  // Simpler than obj.get() == nullptr
        obj.reset(new Singleton());
    return obj.get();
}
273K
  • 29,503
  • 10
  • 41
  • 64
  • yeah but using raw pointers is not a good idea is it? i simply prefer using handler classes like unique_ptr instead of raw pointers. – Osman Sep 14 '22 at 20:03
  • Not right, using raw pointers is a good idea, if you don't keep it for further using out of the context where `getInstance` is called. Look at any C++ code style guide. – 273K Sep 14 '22 at 20:05
  • there might be(which don't think so) cases where pointers might be a little more beneficial but in general handler classes > raw pointers says bjarne stroustrup and many otheres. – Osman Sep 14 '22 at 20:13
  • The problem smart pointers solve is that of ownership. `Singleton` owns the `unique_ptr` and the `unique_ptr` owns the `Singleton` instance. Since ownership is maintained, you can pass around raw pointers until the cows come home, the program exits, and the static variables are all destroyed. Do not try to use the `Singleton` after that (as strange as this sounds, it's possible to do that). – user4581301 Sep 14 '22 at 20:14
  • If the raw pointer offends, change the prototype to `static Singleton& getInstance()` and then `return *obj.get();`. The dangers are exactly the same, but people tend to not screw around with and misuse references quite as badly as they do pointers. – user4581301 Sep 14 '22 at 20:16