Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
c++;单例实现:单例的pimpl习惯用法,优缺点 在C++中实现单体时,我看到了两种存储实现数据的方法:_C++_Oop_Singleton - Fatal编程技术网

c++;单例实现:单例的pimpl习惯用法,优缺点 在C++中实现单体时,我看到了两种存储实现数据的方法:

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

(A) 将所有实现数据放在私有部分,并像往常一样实现类
(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回答了你的问题