想利用继承自C++模板的方式,来生成单例。所引发的奇特现象(或bug)

摘要:

目的:见标题

问题复现:

利用具体类型将C++模板类实例化出单例,然后用不同的类A和B来继承,并导出这俩类让别的dll使用,发现通过A和B得到的单例是同一个单例(内存地址都一样)。

module1.dll里,用Dll.h导出:

#if defined (__KERNEL_BUILD__)
#define HCHXKernel_EXPORT     EXPORT_ATTRIBUTE
#else
#define HCHXKernel_EXPORT     IMPORT_ATTRIBUTE
#endif

//类型

struct Kernel_EXPORT ObjectType
{
    int mMainType;/*主类型,比如:井、雨水口,化粪池,。。。ComponentMainType*/
    int mSubType;/*子类型,就是页数。如果是井。WellSubType*/
    int mExtraType;

    std::wstring mExtraStr; //扩展

//...

};

//接口

struct Kernel_EXPORT ParamComponent
{
    ParamComponent();
    virtual ~ParamComponent();

//...

};

//利用模板来生成单例

template <
    typename AbstractProduct, //接口
    typename ProductTypeKey=std::wstring, //key
    typename ...ArgTypes //其他参数
>
class GenericFactory
{

//.........

//得到具体的唯一实例

inline static GenericFactory<AbstractProduct, ProductTypeKey, ArgTypes...>& GetSingletonInstance()
    {
        static GenericFactory<AbstractProduct, ProductTypeKey, ArgTypes...> unique_generic_factory;
        return unique_generic_factory;
    }

};

//利用具体类型将模板进行实例化,通过继承生成类ParamComponentFactoryAtlasPageNo,并导出。

struct Kernel_EXPORT ParamComponentFactoryAtlasPageNo : public GenericFactory<ParamComponent, ObjectType>
{
    //TestFactory() = delete;
    //~TestFactory() = delete;

};

//利用同样的具体类型将模板进行实例化,通过继承生成类TestFac,并导出。

struct Kernel_EXPORT TestFac : public GenericFactory<ParamComponent, ObjectType>
{
    //TestFactory() = delete;
    //~TestFactory() = delete;

};

module2.dll里:

由于GenericFactory有接受注册的能力。现在用ParamComponentFactoryAtlasPageNo依次注册不同的类(对象),TestFac从不注册。:

void main()

{

ParamComponentFactoryAtlasPageNo::Register<ElbowParamComponent>(LINENAME(g_ParamComponent, __LINE__))(*ElbowParamComponent::GetStaticType());

auto& fac = ParamComponentFactoryAtlasPageNo::GetSingletonInstance();
auto& fac0 = TestFac::GetSingletonInstance();

会发现fac0里面并非为空,它和fac 的地址(&fac, &fac0)一样。而且里面也有内容,和ParamComponentFactoryAtlasPageNo里的一样,即使它从未进行过任何注册操作。

}

分析所导出的符号

用dumpins分析module1,发现导出的符号,并没有ParamComponentFactoryAtlasPageNo和TestFac,只有实例化后的:GenericFactory<ParamComponent, ObjectType>

用vs2015的开发人员命令提示

D:\DevTools\VS2015>dumpbin /exports D:\HchxKernel.dll  >123567.txt

打开123567.txt:

发现导出了用ParamComponent, ObjectType实例化的类,导出了函数GetSingletonInstance(void)。没发现ParamComponentFactoryAtlasPageNo和TestFac的字样。

1、ParamComponentFactoryAtlasPageNo的构造函数(注意?0),TestFac类似

245   F4 0000E8E0 ??0ParamComponentFactoryAtlasPageNo@@QEAA@XZ = @ILT+55515(??0ParamComponentFactoryAtlasPageNo@@QEAA@XZ)

2、ParamComponentFactoryAtlasPageNo的构造函数(注意?1),TestFac类似

??1ParamComponentFactoryAtlasPageNo@@QEAA@XZ = @ILT+104295(??1ParamComponentFactoryAtlasPageNo@@QEAA@XZ)

3、被实例化之后模板,里面的接口GetSingletonInstance(void)

?$TSS0@?1??GetSingletonInstance@?$GenericFactory@UParamComponent@@UObjectType@@$$V@@SAAEAV2@XZ@4HA = ?$TSS0@?1??GetSingletonInstance@?$GenericFactory@UParamComponent@@UObjectType@@$$V@@SAAEAV2@XZ@4HA (int `public: static class GenericFactory<struct ParamComponent,struct ObjectType> & __cdecl GenericFactory<struct ParamComponent,struct ObjectType>::GetSingletonInstance(void)'::`2'::$TSS0)

4、unique_generic_factory是static的名字,被导出了

?unique_generic_factory@?1??GetSingletonInstance@?$GenericFactory@UParamComponent@@UObjectType@@$$V@@SAAEAV2@XZ@4V2@A = ?unique_generic_factory@?1??GetSingletonInstance@?$GenericFactory@UParamComponent@@UObjectType@@$$V@@SAAEAV2@XZ@4V2@A (class GenericFactory<struct ParamComponent,struct ObjectType> `public: static class GenericFactory<struct ParamComponent,struct ObjectType> & __cdecl GenericFactory<struct ParamComponent,struct ObjectType>::GetSingletonInstance(void)'::`2'::unique_generic_factory)

可以发现,如果调用GetSingletonInstance,是只看实例化用的类型(ParamComponent, ObjectType),不看类名(ParamComponentFactoryAtlasPageNo和TestFac)

即使用namespace保护起来,其实只是给TestFac的构造和析构函数保护起来了。GetSingleInstance()所对应的还是那个。

所以在module2里面用auto& fac = NS_CREDCUnitTest::TestFac::GetSingletonInstance();,还是和ParamComponentFactoryAtlasPageNo::GetSingletonInstance();一样,里面有内容。

namespace NS_CREDCUnitTest
{
struct HCHXKernel_EXPORT TestFac : public GenericFactory<ParamComponent, ObjectType/*, std::string&*/>//, public Singleton<ParamComponentFactory>
{
    //TestFactory() = delete;
    //~TestFactory() = delete;

};
}

构造函数:

??0TestFac@NS_CREDCUnitTest@@QEAA@XZ = @ILT+87455(??0TestFac@NS_CREDCUnitTest@@QEAA@XZ)

析构函数:

??1TestFac@NS_CREDCUnitTest@@QEAA@XZ = @ILT+36135(??1TestFac@NS_CREDCUnitTest@@QEAA@XZ)

更有意思的:

而且在module2里面,即使你定义一个类继承自GenericFactory<ParamComponent, ObjectType>,不做import或者export,最后GetSingleInstance引用的结果还是ParamComponentFactoryAtlasPageNo::GetSingleInstance()一样。相当奇特啊。

struct RebarComponentFactory : public GenericFactory<ParamComponent, ObjectType>
{
    //TestFactory() = delete;
    //~TestFactory() = delete;

};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值