首先,我会写一些例子来正确解决这个问题.
首先,我将声明用于创建单例对象的模板(不是自动创建的):
singleton_base.h
template <class Derived>
class SingletonBase
{
public:
static Derived* instance() { assert(s_instance); return dynamic_cast<Derived*>(s_instance); }
protected:
SingletonBase() { assert(s_instance==0); s_instance=this; }
virtual ~SingletonBase() { assert(s_instance); s_instance=0; }
private:
static SingletonBase* s_instance;
};
template <class Derived>
SingletonBase<Derived>* SingletonBase<Derived>::s_instance = 0;
现在我们可以声明从模板派生的任何类,并且每个派生类都应该有自己的s_instance.例如:
child1.h
class Child1 : public SingletonBase<Child1>
{
...
void doSomething();
static void staticInvokeOne();
};
child2.h
class Child2 : public SingletonBase<Child2>
{
...
void doSomethingElse();
static void staticInvokeBoth();
};
我也分别在child1.cpp和child2.cpp中实现了Child的实现.
child1.cpp
void Child1::staticInvokeOne()
{
instance()->doSomething();
}
child2.cpp
void Child2::staticInvokeBoth()
{
Child1::instance()->doSomething();
instance()->doSomethingElse();
}
现在我让Child1和Child2拥有自己的s_instance,并且它们将在给定时刻指向该类的唯一实例.
问题是关于此静态数据成员s_instance的存储.与常规静态数据成员不同,我没有指定应该在哪里分配它.当然,我希望分别在child1.o和child2.o中使用SingletonBase< Child1> :: s_instance和SingletonBase< Child2> :: s_instance,但这是我可以预期或执行的内容吗?
如果我将Child1和Child2放入两个不同的库 – lib1和lib2,问题会变得更加复杂.在Child2 :: staticInvokeBoth()中,有一个对Child1 :: instance()的调用.据我所知,默认gcc的行为是在每个编译单元中生成SingletonBase< Child1> :: s_instance的副本,因此将在lib2中发出一个副本.
它是否还会在lib2中生成SingletonBase< Child1> :: s_instance的副本?当然,SingletonBase< Child1> :: s_instance的一个副本应该在lib1中.如果这两个库后来在一个应用程序中一起使用,我可以确定只有一个SingletonBase< Child1> :: s_instance的实例,并且Child1 :: staticInvokeOne()和Child2 :: staticInvokeBoth()都在使用它吗?
使用这种方法将模板包装在模板中是否通常是安全的,还是有任何缺点?
先感谢您!
解决方法:
对此的答案与任何其他基于模板或内联函数的答案相同 – 唯一的区别是在这种情况下变量最终被标记为放置在读写部分中.
在大多数编译器中,编译器将在它们被引用的每个编译单元中实例化任何所需的模板函数和静态成员变量.编译器还将这些标记为“弱符号”;这意味着,在最后的链接阶段,链接器将任意选择一个发出的副本进入最终的可执行文件.
但请注意,弱符号合并过程通常在静态链接阶段完成.动态链接器不会为您执行此操作.因此,您应该避免在共享库中使用可变(读写)模板静态数据成员.还要避免跨共享库(包括RTTI数据)对只读模板静态数据成员进行地址比较.
一般而言,请记住共享库,跨越ABI边界的模板定义中的任何变化几乎都会破坏您的ABI – 因此最好完全避免在共享库API中使用模板!
标签:c,templates,static-members 来源: https://codeday.me/bug/20191007/1864936.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。