在c ++中实现单例时,我看到了两种存储实现数据的方法:
(A)将所有实施数据放在私有部分并像往常一样实施类 (B)“用于单身人士的pimpl习语”:通过将实现数据放置在'Impl'结构中来隐藏实现数据,该结构可以在实现文件中定义。专用部分仅包含对实现结构的引用。
这是一个概念代码,用于阐明(A)和(B)实施选项的含义:
(A)SingletonClassMembers.hpp:
// a lot of includes required by private section
#include "HelperClass1.hpp"
#include "HelperClass2.hpp"
// some includes required by public section
// ...
class SingletonClassMembers {
public:
static SingletonClassMembers& getInstance();
// public methods
private:
SingletonClassMembers ();
~SingletonClassMembers();
SingletonClassMembers (const SingletonClassMembers&); //not implemented
SingletonClassMembers& operator=(const SingletonClassMembers&); //not implemented
HelperClass1 mMember1;
HelperClass2 mMember2; //and so on
(A)SingletonClassMembers.cpp:
#include "SingletonClassMembers.hpp"
SingletonClassMembers& getInstance() {
static SingletonClassMembers sImpl;
return sImpl;
}
(B)SingletonHiddenImpl.hpp:
// some includes required by public section
// ...
class SingletonHiddenImpl {
public:
static SingletonHiddenImpl& getInstance();
// public methods
private:
SingletonHiddenImpl ();
~SingletonHiddenImpl ();
SingletonHiddenImpl (const SingletonHiddenImpl&); //not implemented
SingletonHiddenImpl& operator=(const SingletonHiddenImpl&); //not implemented
struct Impl;
Impl& mImpl;
};
(B)SingletonHiddenImpl.cpp:
#include "SingletonHiddenImpl.hpp"
#include "HelperClass1.hpp"
#include "HelperClass2.hpp"
struct SingletonHiddenImpl::Impl {
HelperClass1 member1;
HelperClass2 member2;
};
static inline SingletonHiddenImpl::Impl& getImpl () {
static Impl sImpl;
return sImpl;
}
SingletonHiddenImpl::SingletonHiddenImpl ()
: mImpl (getImpl())
{
}
因此,使用(B)方法,您可以更好地隐藏实现细节(与普通类的pimpl习惯用法不同),没有性能损失。我无法想象(A)方法更合适的条件
问题是,将实施数据存储为班级成员(A)有什么好处?
谢谢
答案 0 :(得分:1)
使用案例A有以下好处:
答案 1 :(得分:1)
由于您只有一个单例实例,您实际上可以将助手移动到实现类中作为“静态”,而不要求它们在标题内是私有的。当然你不想初始化它们,直到你开始你的类,所以你会使用某种智能指针,可能是auto_ptr here或boost :: scoped_ptr,或指针有boost :: once初始化(更多线程安全) )在你的单身人士的析构函数中删除。
您可以将此模型称为C,并且在完全隐藏您的实现时可能具有两全其美的效果。
与任何单身人士的情况一样,你需要格外小心,不要乱扔你的构造函数。
答案 2 :(得分:1)
在考虑pimpl的效率时,不是导致开销的堆,而是间接(通过委托完成)。这个委托通常没有优化(至少在我考虑这个时没有;-)),所以除了创建impl的启动(1次)惩罚之外没有大的收益。 (顺便说一句,我在你的例子中没有看到任何委托功能)
所以我认为在正常班级或单身人士中使用pimpl并没有太大区别。我认为在这两种情况下,对于界面有限且实现繁重的类使用pimpl,这是有道理的。