【问题标题】:c++11 Singleton is creating new instancesc++11 Singleton 正在创建新实例
【发布时间】:2017-07-24 19:55:13
【问题描述】:

这是我的单身

class MySingleton {
private:
    int myNumber;
public:
    static MySingleton &get() {
        static MySingleton instance;
        return instance;
    }

    int getMyNumber() const {
        return myNumber;
    }

    void setMyNumber(int myNumber) {
        MySingleton::myNumber = myNumber;
    }
};

这是测试它的代码

MySingleton t1 = MySingleton::get();
t1.setMyNumber(6);
printf("t1: %d \n", t1.getMyNumber());

MySingleton t2 = MySingleton::get();
printf("t2: %d \n", t2.getMyNumber());

现在我得到的输出是

t1: 6 
t2: 0 

但预期的结果是

t1: 6 
t2: 6 

看起来MySingleton::get() 正在创建一个新实例,它当然不应该这样做。

【问题讨论】:

  • 为什么不应该呢?你没有禁止复制或分配。编译器无法解读您想要的单例概念,您必须指定该行为。
  • 请注意,您的单例不是单例。因为它可以被默认构造和复制。
  • 当您调用 setMyNumber(6) 时,您会在单例的副本(名为 t1)上调用它。对get 的下一次调用返回对与之前相同的实例的引用,只是它不知道您对副本所做的更改

标签: c++ c++11


【解决方案1】:

在您的情况下,get() 没有创建副本。对t1t2 的分配正在执行。为避免将其更改为引用:MySingleton& t1 = MySingleton::get()

并且为了避免意外错误删除复制和赋值运算符:

MySingleton(const MySingleton& other) = delete;
MySingleton& operator=(const MySingleton& other) = delete;

【讨论】:

    【解决方案2】:

    原因是您在这些行中创建了实例的副本:

    MySingleton t1 = MySingleton::get();
    MySingleton t2 = MySingleton::get();
    

    并更改副本。

    要使其工作,您必须添加参考:

    MySingleton& t1 = MySingleton::get();
    MySingleton& t2 = MySingleton::get();
    

    另请注意,经典的单例设计假定删除了复制构造函数和复制赋值运算符以避免此类错误:

    class MySingleton {
        private:
            // ...
        public:
            // ...
            MySingleton(const MySingleton&) = delete;
            void operator=(const MySingleton&) = delete;
    };
    

    附:您可能会发现 this discussion 很有用。它显示了使用 C++ 的单例模式的实现细节。

    【讨论】:

    • 因此需要定义一个 (private) 构造函数。 MySingleton():myNumber(0){}; 也许?
    • @Persixty 我为 OP 提供了与他的问题相关的部分实现。他可能很容易找到完整的实现,所以我决定不发布它。是的,构造函数当然应该是私有的。
    【解决方案3】:

    您正在复制单例而不是获取参考:

    MySingleton &t1 = MySingleton::get();
    

    将copy-an move-assignment和-constructors标记为delete,并将构造函数和析构函数设为私有:

    class MySingleton
    {
    public:
        MySingleton(const MySingleton&) = delete;
        void operator=(const MySingleton&) = delete;
    
        MySingleton(MySingleton&&) = delete;
        void operator=(MySingleton&&) = delete;
    
    private:
        MySingleton() = default;
        ~MySingleton() = default;
    
    };
    

    请注意,您可能只需要一个全局变量而不是单例。

    【讨论】:

      【解决方案4】:

      您将 t1 和 t2 都声明为类的实例,而不是对该类的引用。

      get 函数已正确实现,但每个实例都是在分配时构造的。 请注意,将您的构造函数设为私有可以防止编译时出现此错误。

      我建议阅读有关如何在 c++ 中实现单例的教程,以学习一些好的实践,或者简单地使用现有的精心制作的实现。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-01-23
        • 1970-01-01
        • 2016-03-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多