c++;单例实现:单例的pimpl习惯用法,优缺点 在C++中实现单体时,我看到了两种存储实现数据的方法:
(A) 将所有实现数据放在私有部分,并像往常一样实现类c++;单例实现:单例的pimpl习惯用法,优缺点 在C++中实现单体时,我看到了两种存储实现数据的方法:,c++,oop,singleton,C++,Oop,Singleton,(A) 将所有实现数据放在私有部分,并像往常一样实现类 (B) “单例pimpl惯用法”:通过将实现数据放置到“Impl”结构中隐藏实现数据,该结构可以在实现文件中定义。Private部分仅包含对实现结构的引用 以下是一个概念代码,以澄清我所说的(a)和(B)实施选项的含义: (A) SingletonClassMembers.hpp: // a lot of includes required by private section #include "HelperClass1.hpp" #i
(B) “单例pimpl惯用法”:通过将实现数据放置到“Impl”结构中隐藏实现数据,该结构可以在实现文件中定义。Private部分仅包含对实现结构的引用 以下是一个概念代码,以澄清我所说的(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
//私人部门要求提供大量服务
#包括“HelperClass1.hpp”
#包括“HelperClass2.hpp”
//一些包括公共部分要求的内容
// ...
类SingletonClassMembers{
公众:
静态SingletonClassMembers&getInstance();
//公共方法
私人:
SingletonClassMembers();
~SingletonClassMembers();
SingletonClassMembers(const SingletonClassMembers&);//未实现
SingletonClassMembers&operator=(const SingletonClassMembers&);//未实现
HelperClass1 mMember1;
HelperClass2 mMember2;//依此类推
(A) SingletonClassMembers.cpp:
#include "SingletonClassMembers.hpp"
SingletonClassMembers& getInstance() {
static SingletonClassMembers sImpl;
return sImpl;
}
#包括“SingletonClassMembers.hpp”
SingletonClassMembers&getInstance(){
静态单例类成员siml;
返回siml;
}
(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;
};
//一些包括公共部分要求的内容
// ...
类SingletonHiddenImpl{
公众:
静态SingletonHiddenImpl&getInstance();
//公共方法
私人:
SingletonHiddenImpl();
~SingletonHiddenImpl();
SingletonHiddenImpl(const SingletonHiddenImpl&);//未实现
SingletonHiddenImpl&operator=(const SingletonHiddenImpl&);//未实现
结构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())
{
}
#包括“SingletonHiddenImpl.hpp”
#包括“HelperClass1.hpp”
#包括“HelperClass2.hpp”
结构SingletonHiddenImpl::Impl{
助手类别1成员1;
助手类别2成员2;
};
静态内联SingletonHiddenImpl::Impl和getImpl(){
静态Impl-siml;
返回siml;
}
SingletonHiddenImpl::SingletonHiddenImpl()
:mImpl(getImpl())
{
}
因此,使用(B)方法,您可以更好地隐藏实现细节,并且(与普通类的pimpl习惯用法不同)没有性能损失。我无法想象(A)方法更合适的情况
问题是,将实现数据存储为类成员有什么好处(A)?
感谢您使用案例A有以下好处:
可以减少类SingletonClassMembers和SingletonHiddenImpl之间的依赖关系
如果您试图通过依赖项注入避免对(1)的限制,则不需要在SingletonClassMembers类中创建configurator模式
这种情况很弱,但无论如何:维护单个类很简单
在多线程环境中,您需要同时支持两个类的同步机制,而在单个类中只需要单锁
由于您只有一个singleton实例,因此实际上可以将助手作为“静态”移动到实现类中当然,在你启动你的类之前,你不想初始化它们,这样你就可以使用某种智能指针,可以是auto_ptr这里或者boost::scoped_ptr,或者是带有boost::once initialization(更线程安全)和singleton的析构函数中的deletes的指针
您可以将此模型称为C,并且在完全隐藏您的实现时,它可能兼有这两个方面的优点
与任何单例一样,您需要格外小心,不要加入构造函数。在考虑pimpl的效率时,导致开销的不是堆,而是间接(通过委托完成)。这种委托通常没有得到优化(至少在我考虑这一点时没有;-)),因此,除了创建impl的启动(1次)惩罚之外,没有什么大的好处。(顺便说一句,我在您的示例中没有看到任何委托函数)
因此,我看不出在普通类或单例类中使用pimpl有多大区别。我认为在这两种情况下,在接口有限且实现繁重的类中使用pimpl是有意义的。你误解了我;)单例类成员和单例HIDDENIMPL类之间根本没有依赖关系。它们都是为de提供的演示不同的存储实现数据的方法在第4点,主单例类是Impl的包装器,可能只返回它,在这种情况下,只有Impl需要正确的同步访问。实际上,a和B之间的决定应该由是否确实需要隐藏成员1和2-i的存在来决定你有成员1和成员2是商业敏感的吗?只要你的敏感业务逻辑隐藏在访问器中-你真的在乎吗?如果是这样,B,否则为什么过于复杂?@konstantin-我明白你的意思,我的答案是正确的,很抱歉对类使用了相同的名称。我的观点是:在第二种情况下,你需要一些解决方案来实现front类和impl类之间的nt依赖注入。@Nim-很好的注释,+1。我只需要做一点注释:@konstantin问:“将实现数据存储为类成员(A)有什么好处”-所以我只想指出这一点。关于多线程的另一件事。多线程环境中的Singleton也应该是安全的(为了避免同时从不同的线程创建两个实例)@Nim-在我看来,几乎所有人都会同意使用前向声明而不是免费的\#includes来减少编译时依赖性更好出于同样的原因1.单例,已经讨论过2.Pimpl ideom,已经讨论过了。我看不出这会带来什么新东西?Pimpl ideom r回答了你的问题