Это правильная реализация Singleton с общим ptr в MSVC 2013? - PullRequest
0 голосов
/ 30 июня 2018
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;
};

читал двойную проверку блокировки http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/, но мне также нужно использовать shared_ptr для собственного необработанного указателя.

Из документации я знаю, что я не могу использовать shared_ptr в качестве шаблона для std :: atomic (§29.5 1 в N3290)

Обновление: моя реализация кажется правильной (хотя и не элегантной) - так как она прошла проверку кода. Спасибо всем!

1 Ответ

0 голосов
/ 30 июня 2018

Вам не нужен указатель, будь он необработанным или общим, просто используйте ссылку:

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_;
};

Meyers 'Singleton гарантированно безопасен для потоков.

Используйте экземпляр mutex для синхронизации любых операций, выполняемых с вашим синглтоном, в случае необходимости обеспечения безопасности потока.

...