【问题标题】:How to ensure that there is at least one instance of a class?如何确保至少有一个类的实例?
【发布时间】:2013-04-18 15:51:46
【问题描述】:

我需要确保在程序执行期间始终存在某个类的至少一个实例。单身人士不会这样做,因为(除其他原因外)我将来可能需要更多实例。一个静态类也可以,但感觉就像是全球化......我还想要一些私有成员,包括函数和变量。

我曾考虑将 shared_ptr 保存在安全的地方,但这似乎是一个粗略的 hack。

有标准的方法吗?

编辑

澄清:这不是能够检查实例是否仍然存在的问题。实例必须始终存在。原因是类中有静态成员变量,应该保持它们的状态。

【问题讨论】:

  • 为什么你需要某个类的至少一个实例?
  • 您将如何访问此实例?可以懒惰构造吗?
  • @DanF:为了不松散一些静态成员变量的状态。
  • @Luc:是的。这甚至是可取的。
  • @steffen - 静态成员独立于类。您可以在没有类实例的情况下使用它们,例如 class_name::member

标签: c++ static singleton


【解决方案1】:

我需要确保在程序执行期间始终存在某个类的至少一个实例。

所以我想解决方案首先要决定谁负责存储它。

您可以:将其存储在类内部(静态)或将其返回给调用者/客户端上下文(并依赖客户端上下文来保留它)。既然您说“单身人士不会做”,那么解决方案应该如下所示:

class TheClass
{
public:
    // this doesn't have to be a std::shared_ptr<WithContext>
    // and probably shouldn't be (see below)
    typedef <implementation-defined> GlobalContext;

    GlobalContext InitContext(); // return instance
};

void main( /* ... */ )
{
    // do this before any code that uses TheClass instances
    auto global_execution_context = TheClass::InitContext();

    // rest of your application code goes here
}

我曾考虑将 shared_ptr 保存在安全的地方,但这似乎是一个粗略的技巧。

您认为它的缺点是什么?如果是因为它是一个模糊的依赖项,您可以为其添加测试,或者在上下文被删除/影响/不存在时抛出异常。您还可以在 TheClass 的构造函数中请求对您的上下文的引用。

您不应该让 GlobalContext 成为 std::shared_ptr 但它是自己的类型的原因是,这就是您的实际要求:

您需要一种(新)类型的对象来保持实例之间的 TheClass 的共同状态。

【讨论】:

    【解决方案2】:

    我总是使用内部静态计数器来实现这一点,该计数器在构造函数中递增并在析构函数中递减。

    是的,你检查“至少一个实例”的方法肯定是静态的。

    更新:好的,我在这里看到答案有错误,所以我发布我的答案:

    class Test
    {
    private:
      static int m_count;
    public:
      Test() { ++m_count; }
      Test(const Test&) { ++m_count; }
    
      ~Test()
      {
        --m_count;
      }
    
      static bool hasInstance()
      {
        return (m_count > 0);
      }
    };
    
    int Test::m_count = 0;
    
    int main()
    {
        return 0;
    }
    

    【讨论】:

      【解决方案3】:

      使用静态成员并将其设置在构造函数/析构函数中:

      class Test
      {
        static int i;
      public:
        Test()
        {
          i++;
        }
      
        Test(const Test &t) // It's suspicious 
        {
          i++;
        }
      
        ~Test()
        {
            i--;
        }
      
        static bool hasInstance()
        {
          return i>0;
        }
      };
      
      static int Test::i = 0;
      

      那么,你知道Test有没有实例。

      【讨论】:

      • 请在 hasInstance() 中添加 'static' 修饰符。这样你的答案就是我的方法的 100% 说明。
      • BTW 错误:m_hasInstance 不应在析构函数中重置!!!可能带计数器的解决方案更好。
      • 您还需要在复制构造函数中增加(或阻止复制)。
      • @Bleep Bloop 总的来说你是对的,+1。但是复制可能会被阻止,是吗? ;-)
      • MM +1,现在可以添加复制构造函数了吗? ))
      【解决方案4】:

      一种包含所有实例集合的工厂类怎么样?

      类似:

      template<typename T>
      class least_one_factory
      {
          static std::vector<T> instances_;
      
      public:
          least_one_factory()
          {
              // Make sure there is an instance of `T` in our collection
              instance_.push_back(T());
          }
      
          T& get()
          {
              return instances_.front();
          }
      
          T& get(int n)
          {
              return instances_.at(n);
          }
      
          T& create()
          {
              instances_.push_back(T());
              return instances_.back();
          }
      
          int count() const
          {
              return instances_.size();
          }
      
          operator T&()
          {
              return get();
          }
      };
      
      template<typename T>
      std::vector<T> least_one_factory<T>::instances_;
      

      现在你可以这样做了:

      struct some_class {};
      
      least_one_factory<some_class> some_class_factory;
      

      变量some_class_factory 将包含至少一个some_class 的实例。您可以通过some_class_factory.get() 获得它。如果some_class_factory是一个全局变量,那么some_class的实例将会在你的程序被加载之前在main被调用之前被创建。

      【讨论】:

      • 这是我想要的更多(但不完全是);)如果可能的话,我想让它对其余代码透明,而不必编写.get()
      • @steffen 添加了转换运算符,现在可以用作some_class var = some_class_factory; 转换运算符只返回第一个实例。但是,对于以下实例,很难使其更加“透明”,尤其是它们的创建。
      猜你喜欢
      • 2023-03-20
      • 1970-01-01
      • 2022-01-05
      • 1970-01-01
      • 1970-01-01
      • 2022-01-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多