就在前几天,我看到了使用所谓的单例模式的代码。
的含义class MySingleton{
public:
void foo() { ... }
static MySingleton&get_instance(){
static MySingleton singleton;
return singleton
}
private:
MySingleton(){ ... }
~MySingleton(){ ... }
int bar;
};
我确实知道为什么会这样做:
但是我不明白为什么这种做事方式优于一些免费功能。我实现它的方法是放
namespace some_name{
void foo();
}
标题中的和
namespace some_name{
void foo(){
...
}
}
在实现文件中。如果我需要初始化和/或清理,我要么添加一些必须显式调用的函数,要么添加
namespace{
class Dummy{
Dummy(){ ... }
~Dummy(){ ... }
}dummy;
}
进入实施文件。
我知道这是从语义的角度来看单例,但是我看到第一个变体在C ++代码中使用得比第二个更常见。为什么?我认为第二个版本略胜一筹,所以我问自己是否遗漏了一些明显的东西。
您能否解释一下为什么每个人都使用第一个变体?我没有看到在C语言中做旧事情的单一优势。
答案 0 :(得分:7)
根据党的路线(E. Gamma,R。Helm,R。Johnson和J. Vlissides。Design Patterns: Elements of Reusable Object-Oriented Software。Addison-Wesley,Reading,MA,1995,p.128),单身人士提供与您提出的解决方案相比具有以下优势。
话虽如此,在大多数情况下我认为额外的复杂性过多,很少使用我编写的代码中的模式。但是,当您设计其他人将使用的API时,我可以看到它的价值。
答案 1 :(得分:4)
这有帮助吗?
What is so bad about singletons? http://steve.yegge.googlepages.com/singleton-considered-stupid
重新说明:单身人士是一个美化的全球化,因此只需将其“实施”为全球性的。
答案 2 :(得分:3)
static MySingleton singleton;
的构造在第一次使用时被调用。 (当调用get_instance()
时。)如果从未调用它,它永远不会调用构造函数。您的方法将在静态构造时调用构造函数。前一种方法允许调用构造函数的顺序和时间。您的方法将根据编译器静态初始化顺序对每个单例的构造进行排序。
答案 3 :(得分:1)
要让函数+静态数据模拟单例模式,将依赖于C ++的文件范围和单独编译。这些是编译器构造而不是语言构造。单例类模式允许数据封装,而不管编译单元的位置如何;它被正确封装,即使它是在具有其他类和函数的文件中定义的。
此外,它实际上不会模拟单例模式的行为,而只是模拟静态对象的行为,这不是同一件事。单例的生命周期与包含它的过程的生命周期无关。正确形成的单例在第一次使用时被实例化,而静态数据在main()启动之前被实例化和初始化。这可能是一个问题,如果说对象的构造依赖于某些其他运行时实体的存在。此单例对象在实例化之前不占用任何内存(除了其静态实例指针)。它也可能在任何时候被破坏和重新创建,实际上很多次。
请注意,如果修改单例以使构造函数受保护而不是私有,则可以对其进行子类化(从而轻松应用重用单例模式),不能使用静态对象或具有所有静态成员的对象执行此操作,或者使用带有文件范围的静态数据的函数,或者您尝试正确执行此操作的任何其他方式。
您的建议本身没有任何问题,只要您知道它不是单身模式,并且缺乏灵活性。
答案 4 :(得分:0)
使用自由函数的问题在于,默认情况下这些函数不会获得共享持久行为,就像您的单例类可以使用成员变量和常量一样。
你可以继续使用静态全局变量来做同样的事情,但是对于想要弄明白的人来说,这使得他们必须看到的范围几乎无限地理解这些例程的行为。使用单例类,一切都很好地组织成一个类供读者检查。
答案 5 :(得分:0)
就个人而言,当我想控制第一次执行构造函数时,我会使用单例。
例如; 如果我的日志系统有单例,则打开文件进行写入的代码将被放入单例构造函数中,该函数称为like; Logger.instance();在我的启动过程中。 如果我使用命名空间,我将拥有该控制权。