【问题标题】:Singleton initialization单例初始化
【发布时间】:2011-04-12 13:54:01
【问题描述】:

我在我的代码中实现了Singleton design pattern

假设是:

class Singleton
{
  Singleton () {}
  static Singleton* s;
public:
  static Singleton* Get () {
    if (!s)
      s = new Singleton ();
    return s;
  }
};

令我困惑的是这种模式的“初始化”。 在 .cpp 我放:

SingletonPointer* SingletonClass::s (0);

但我不明白如何访问定义s,因为它是private。 这怎么可能?

TIA, 吉尔

【问题讨论】:

  • 为什么要从 void 函数返回值? ;)
  • 哎呀!猜猜如果我复制'n'pasteed会更好:D感谢您指出。我马上去拿。

标签: c++ singleton private-members


【解决方案1】:

使用单例模式的最佳方法是根本不使用它。

单例为什么不好的简要总结:

  1. 它们是具有特殊限制的全局变量。出于自身原因,全球人已经够糟糕了;让它们成为单例只会放大坏处。
  2. 如果您真的只需要一个对象的实例,那么只需创建一个。如果您需要一种特殊的设备来确保您不会制作多个设备,那么您的代码的语义就有问题。让它成为一个单例并不能解决问题,它只会用新的问题解决它。
  3. 单例不能很好地处理线程。线程已经够难了。不要让它们变得更难。

使用单例并不能解决任何问题。它只是将错误的语义应用于现有代码,使该代码的未来扩展变得困难或不可能(如果明天需要两个怎么办?),并增加了新问题。长话短说,只是不要使用它们。

【讨论】:

  • @RedX:我会对这样的文章感兴趣,我知道有很多缺点,但最好将它们形式化以供将来参考:)
  • @Matthieu:确实,我反对单例“模式”,而不是使用全局变量(我同意这有时是一个很好的解决方案)。我从来没有听说过阻止一个类的多个实例的有效案例,也没有看到 Singletons 被用作伪装的全局变量以外的任何东西。如果有人有例子,我会很感兴趣。
  • @James:我不同意。在这种情况下,我的断言“如果你只需要一个,那么就创建一个”适用。记录器对象通常由某些应用程序类型的对象拥有,您只创建其中一个。你不需要去寻找它。就做my_app->GetLogger()->DoTheThing();
  • @James:那就不要创建第二个了。
  • @James Kanze:您可以通过全局函数访问它来解决初始化顺序问题,其中它是一个静态变量(有一些关于线程安全的警告[将在 C+ +0x,并且已经在大多数编译器中修复]和销毁顺序),或者在问题中创建(如果需要,解决线程安全问题)。这是一个与防止多个实例完全不同的问题,除了“因为某些疯子将其放入规范中”之外,您还没有提供一个示例来说明为什么要这样做。
【解决方案2】:

静态字段除了声明之外还必须有定义。声明通常放在 .h 文件中的类声明中,而定义几乎总是放在 .cpp 文件中。静态变量的定义是必须的,因为它们必须被初始化。

但即使定义在类主体之外,甚至在完全不同的文件中,也不意味着它不是类的一部分。 SingletonClass:: 使其成为类定义的一部分(与类声明相反),因此它可以“访问”私有字段。

类体之外定义的方法也是如此,例如:

// A.h
class A
{
private:
    int b;
public:
    A(int x) : b(x)
    {}

    Do();
}

// A.cpp
A::Do()
{
    return b;
}

【讨论】:

  • 现在很清楚了。感谢您的解释。我没有想到我们在定义类方法时总是这样做。
【解决方案3】:

在初始化代码中,您不是在访问Singleton::s,而是在定义它。

【讨论】:

  • 要点:这是关于定义而不是访问。不过,如果它是私有的,怎么可能在类之外定义呢?
【解决方案4】:

类的所有方法都可以访问私有变量。您访问 s 变量的唯一位置是在属于同一类的方法 Get() 中。

如果你想从外部访问s,你不能直接这样做,但你必须调用Get()方法(这是公共的)并且该方法实际上会为您返回 s

用法:

Singleton * s = SingletonClass::Get();

【讨论】:

    【解决方案5】:

    它可以通过Get 从外部访问(如果您指定了适当的类型)。它是private 的事实并不能阻止该方法返回指向它的指针。 private 的成员只是阻止对它的访问按名称

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-20
      • 2018-06-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多