使用std::mutex和std::atomic出现链接问题

5

I have this:

Singleton.h

#ifndef SINGLETON_H
#define SINGLETON_H

#include <atomic>
#include <mutex>

class Singleton
{
public:
    static std::atomic<Singleton*> Singleton::m_instance;
    static std::mutex Singleton::m_mutex;
    static Singleton* getInstance();

    Singleton();
    ~Singleton();
};

#endif

Singleton.cpp

#include "Singleton.h"

Singleton::Singleton()
{
}

Singleton* Singleton::getInstance() 
{
    Singleton* tmp = m_instance.load(std::memory_order_relaxed);
    std::atomic_thread_fence(std::memory_order_acquire);
    if (tmp == nullptr) 
    {
        std::lock_guard<std::mutex> lock(m_mutex);
        tmp = m_instance.load(std::memory_order_relaxed);
        if (tmp == nullptr) 
        {
            tmp = new Singleton;
            std::atomic_thread_fence(std::memory_order_release);
            m_instance.store(tmp, std::memory_order_relaxed);
        }
    }
    return tmp;
}

Singleton::~Singleton() {}

main.cpp

#include "Singleton.h"
#include <iostream>
int main()
{
    Singleton* singleton = Singleton::getInstance();
    std::cout << "Hello World!" << std::endl;
    return 0;
}

当我尝试构建时,我会收到这些错误(Visual Studio):
错误1:error LNK2001: 未解析的外部符号“public: static struct std::atomic Singleton::m_instance”(?m_instance@Singleton@@2U?$atomic@PAVSingleton@@@std@@A) c:...Singleton.obj Singleton
错误2:error LNK2001: 未解析的外部符号“public: static class std::mutex Singleton::m_mutex”(?m_mutex@Singleton@@2Vmutex@std@@A) c:\Users\InusualZ\documents\visual ...Singleton.obj Singleton
1个回答

7

您需要在源文件中定义静态成员变量,而不仅仅是在类定义中声明它们:

std::atomic<Singleton*> Singleton::m_instance;
std::mutex Singleton::m_mutex;

你可能会感兴趣,使用简单的本地静态变量,你可以实现几乎完全相同的惰性线程安全初始化:
Singleton* Singleton::getInstance() {
    static Singleton instance;
    return &instance;
}

这个修复了内存泄漏问题,但如果你尝试从另一个静态变量的析构函数中访问它,则会引入潜在的死亡陷阱。在C++中没有办法实现Singleton反模式而不出现某种问题。你应该重新考虑单例是否适合你的设计。根据我的经验,它永远不是一个好选择。


我已经尝试了那些方法,但是我读到在VS中它们不能正常工作。 - InusualZ
顺便问一下,为什么我需要两次声明这个变量? - InusualZ
@InusualZ:你不需要两次声明它们。你需要定义它们,并将其声明为类成员。 - Mike Seymour
我真的不明白你的意思。 - InusualZ
1
@InusualZ:你已经在类中声明了静态成员。这告诉编译器它们存在,并且在程序的某个地方被定义。你还必须在程序的某个地方(一个源文件中)定义它们,以便为它们分配存储空间。因此,请将我第一个片段中的两行代码放入“Singleton.cpp”源文件中,以便在那里定义变量。这将修复链接错误,该错误是由缺少定义引起的。 - Mike Seymour

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接