1
struct Foo {
    int i_;
    Foo(int i) :i_(i) { std::cout << "Foo:" << i_ << "\n"; }
    ~Foo() { std::cout << "~Foo" << i_ << "\n"; }
};

class FooSingleton
{
public:
static std::weak_ptr<Foo> GetInstance()
{
    auto tmp = std::atomic_load(&instance);

    if (tmp == nullptr) {
        std::lock_guard<std::mutex> lock(mutex1);
        tmp = std::atomic_load(&instance);
        if (tmp == nullptr) {
            tmp = std::make_shared<Foo>(2);
            std::atomic_store(&instance, tmp);
        }
    }
    return tmp;
}
private:
static std::mutex mutex1;
static std::shared_ptr<Foo> instance;
};

Was reading Double-check locking http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/, but I also need using shared_ptr to own raw pointer.

From documentation I know, that I can't use shared_ptr as template for std::atomic (§29.5 1 in N3290)

Update: my realization seems to be right (although it not elegant) - as it passed code review.Thanks to all!

  • 3
    I would really suggest you use a [Meyers' Singleton](https://stackoverflow.com/questions/17712001/how-is-meyers-implementation-of-a-singleton-actually-a-singleton) if you are going to use a singleton. – NathanOliver Jun 30 '18 at 16:01
  • Related: https://stackoverflow.com/questions/1661529/is-meyers-implementation-of-the-singleton-pattern-thread-safe You probably don't need a `shared_ptr`. – πάντα ῥεῖ Jun 30 '18 at 16:01
  • I don't want initialize instance, unless GetInstance() called. I shoud've wrote it in the post. Also, I work in msvc-2013, in link above: support in msvc-2015 – Игорь Бондаренко Jun 30 '18 at 16:07
  • This is definitely one of those implementations use of which leads to usual whining that "singletons are bad for testing" etc. because you give up control over singleton object lifetime and hard code thread-safe lazy instance creation. `shared_ptr` here is completely pointless because object ownership is not shared, as well as atomic functions inside of mutex-protected block. – user7860670 Jun 30 '18 at 16:15
  • @ИгорьБондаренко _"I don't want initialize instance, unless GetInstance() called"_ My proposed solution exactly does this. – πάντα ῥεῖ Jul 01 '18 at 23:03

1 Answers1

1

You don't need a pointer be it raw or shared at all, just use a reference:

struct Foo {
    int i_;
    Foo(int i) :i_(i) { std::cout << "Foo:" << i_ << "\n"; }
    ~Foo() { std::cout << "~Foo" << i_ << "\n"; }
};


class FooSingleton
{
public:
static FooSingleton& GetInstance()
                // ^
{
    static FooSingleton theInstance;
    return theInstance;
}

Foo foo() {
    std::lock_guard<std::mutex> lock(mutex1);
    return Foo;
}
void foo(const Foo& value) {
    std::lock_guard<std::mutex> lock(mutex1);
    foo_ = value;
}
private:
    FooSingleton() : foo_(42) {
    }
    std::mutex mutex1;
    Foo foo_;
};

The Meyers' Singleton is guaranteed to be thread safe.

Use the instance mutex to synch any operations done with your singleton in case thread safety is necessary.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190