其他分享
首页 > 其他分享> > c – 静态模板数据成员存储

c – 静态模板数据成员存储

作者:互联网

首先,我会写一些例子来正确解决这个问题.

首先,我将声明用于创建单例对象的模板(不是自动创建的):
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