C++11 使用共享ptr实现单例类 #包括 #包括 使用名称空间std; 课堂演示{ 静态共享ptr d; 演示(){} 公众: 静态共享\u ptr getInstance(){ 如果(!d) d、 重置(新演示); 返回d; } ~Demo(){ cout

C++11 使用共享ptr实现单例类 #包括 #包括 使用名称空间std; 课堂演示{ 静态共享ptr d; 演示(){} 公众: 静态共享\u ptr getInstance(){ 如果(!d) d、 重置(新演示); 返回d; } ~Demo(){ cout,c++11,C++11,这不是线程安全的:两个线程调用getInstance会导致数据竞争。常用的方法是使用函数范围静态变量: #include <iostream> #include <memory> using namespace std; class Demo { static shared_ptr<Demo> d; Demo(){} public: static shared_ptr<Demo> getInstance(){

这不是线程安全的:两个线程调用
getInstance
会导致数据竞争。常用的方法是使用函数范围静态变量:

#include <iostream>
#include <memory>

using namespace std;

class Demo {
    static shared_ptr<Demo> d;
    Demo(){}
public:    
    static shared_ptr<Demo> getInstance(){
        if(!d)
        d.reset(new Demo);
        return d;
    }
    ~Demo(){
        cout << "Object Destroyed " << endl;
    }

};

//    shared_ptr<Demo> Demo::d(new Demo); // private ctor is accepted 

shared_ptr<Demo> Demo::d;

int main()
{
    shared_ptr<Demo> d(Demo::getInstance());
    cout << d.use_count() << endl;

   return 0;
}
这是一个单例的教科书实现(好吧,是其中之一)



Re:使用私有构造函数初始化。我不确定我是否理解您的困惑的本质。您是否在问为什么
Demo::getInstance
可以使用
Demo
的私有构造函数?因为它是
Demo
的成员,并且类的成员可以访问该类的私有成员。您是否在问为什么
Demo::getInstance
可以调用
共享的\u ptr::reset()
传递
演示*
指针吗?因为
reset()
shared\u ptr
的一个公共成员函数,以指针作为参数。您认为这个过程的哪一部分有争议?

我上面的第二个问题是,为什么私有构造函数在实例化静态成员时调用了类外的构造函数

static Demo& getInstance(){
  static Demo d;
  return d;
}
//共享的\u ptr Demo::d(新的Demo);//接受私有的
我认为返回本地静态不会起作用,请参见下面的示例对象销毁两次

//    shared_ptr<Demo> Demo::d(new Demo); // private ctor is accepted 
#包括
使用名称空间std;
课堂演示{
公众:
静态演示&getInstance(){
静态演示d;
返回d;
}
~Demo(){
cout的一些评论有助于讨论。静态变量将在应用程序退出时被销毁,因此我们不需要在上述阶段使用智能指针

“如果多个线程试图同时初始化同一个静态局部变量,则初始化只发生一次(对于std::call_once的任意函数,可以获得类似的行为)

注意:此功能的通常实现使用双重检查锁定模式的变体,这将已经初始化的本地静态的运行时开销减少到单个非原子布尔比较。 (从C++11开始)


块作用域静态变量的析构函数在程序退出时调用,但仅当初始化成功时才调用。“

getInstance()的静态变量不起作用,Ithink@IgorTandetnik,我测试了您的getInstance()在一个多线程的紧循环中,它工作得很好,但是你能解释一下发生了什么吗?为什么演示只有一次?没有检查Null pTr,这是什么魔术?@卡罗琳贝尔特拉有趣的说,这个C++语言的特性通常被称为编译器自动生成代码T。hat执行必要的同步。@IgorTandetnik,现在更清楚了,谢谢。我目前在Asio异步应用程序中传递了一个指向单个数据库池实例的共享指针。它工作得很好,但看起来很凌乱。使用单个实例会更干净,但关于多线程的历史负面信息太多eaded/singleton应用程序。在我的紧密循环中(数亿次迭代)我遇到过0个问题,但我想知道你是否相信你的应用程序中的一个单独的DB实例,特别是C++ 11线程安全的静态初始化保证。再次感谢。我的项目中使用了CalnIn BelTrn。没有一个发生管理数据库连接,但是我不明白为什么会这样。不同之处。您确实知道,在执行
Demo l=Demo::getInstance();
之后,您将得到一个单例的副本,因此您将不再有单例了?将其设置为
Demo&l=Demo::getInstance();
(注意符号)。然后标记
Demo
的复制构造函数已删除,如
Demo(const Demo&)=delete;
,这样您的原始示例就不会再编译了。如果可以复制,它就不算是一个单例了,不是吗?单例更像是一个反模式,所以我建议不要实现它们。它们与全局变量没有太大的不同。虽然许多人都同意单例使用不当可能会有问题,但我不这么认为我不认为在这里批评他们特别有用——这无助于提问者解决问题。
//    shared_ptr<Demo> Demo::d(new Demo); // private ctor is accepted 
#include <iostream>

using namespace std;

class Demo {
public:
    static Demo & getInstance(){
        static Demo d;
        return d;
    }
    ~Demo(){
        cout << "Demo destroyed" << endl;
    }
};

void fun(){
    Demo l = Demo::getInstance();

}
int main()
{
    fun();
   cout << "Hello World" << endl; 
}