2011-02-07 3 views
2

Сначала я напишу пример, чтобы правильно решить вопрос.Хранилище данных с элементами статического шаблона

Прежде всего, я объявлю шаблон будет использоваться для создания одноплодного объекта (не автоматически создаются): 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 соответственно.

child1.cpp

void Child1::staticInvokeOne() 
{ 
    instance()->doSomething(); 
} 

child2.cpp

void Child2::staticInvokeBoth() 
{ 
    Child1::instance()->doSomething(); 
    instance()->doSomethingElse(); 
} 

Теперь у меня есть Child1 и Child2 имеет свою собственную s_instance и они указывают на единственный экземпляр этого класса в данный момент.

Вопрос о хранении этого статического члена данных s_instance. В отличие от обычных статических элементов данных, я не указал, где он должен быть выделен. Я бы, конечно, хотел бы иметь SingletonBase<Child1>::s_instance и SingletonBase<Child2>::s_instance в child1.o и child2.o соответственно, но это то, что я могу ожидать или обеспечить соблюдение?

вопрос становится более сложным, если я ставлю Child1 и Child2 на две библиотеки - Lib1 и Lib2. Внутри Child2::staticInvokeBoth() есть звонок Child1::instance(). Насколько я понимаю, поведение gcc по умолчанию - генерировать копию SingletonBase<Child1>::s_instance в каждом блоке компиляции, поэтому один экземпляр будет испускаться в lib2.

Будет ли также произведена копия SingletonBase<Child1>::s_instance в lib2? Определенно, одна копия SingletonBase<Child1>::s_instance должна быть в lib1. Если эти две библиотеки позже будут использоваться вместе в одном приложении, могу ли я быть уверенным, что существует только один экземпляр SingletonBase<Child1>::s_instance и что оба его используют Child1::staticInvokeOne() и Child2::staticInvokeBoth()?

Насколько безопасно использовать этот подход со статикой, завернутой в шаблон, или есть какие-то недостатки?

Спасибо заранее!

ответ

4

Ответ на этот вопрос аналогичен любой другой основе на основе шаблона или встроенной функции - единственная разница заключается в том, что в этом случае переменная заканчивается тем, что помечена для размещения в разделе «чтение-запись».

В большинстве компиляторов компилятор будет создавать любые необходимые функции шаблона и статические переменные-члены в в каждом модуле компиляции, на который они ссылаются в. Компилятор также будет отмечать их как «слабые символы»; это означает, что на этапе финальной ссылки компоновщик будет произвольно выбирать одну из эмитированных копий, чтобы перейти в окончательный исполняемый файл.

Обратите внимание, однако, что процесс консолидации слабых символов обычно выполняется на этапе статической компоновки. Динамический компоновщик будет не сделайте это за вас. Таким образом, вы должны избегать использования изменяемых (read-write) шаблонов статических данных в общих библиотеках. Также избегайте сопоставления адресов для элементов статических данных только для чтения в разделяемых библиотеках (включая данные RTTI).

И помните, в общем, с общими библиотеками, что почти любое изменение в определениях шаблонов, которые пересекают ABI boundrary, приведет к поломке вашего ABI - так что, вероятно, лучше всего избегать шаблонов в общих библиотечных API!

+0

Hm ... Это также относится к общим библиотекам? Будут ли эти имена разрешаться во время выполнения динамическим компоновщиком (предполагая linux)? Может ли он вводить в заблуждение DT_SYMBOLIC? – nyrl

+0

Общие библиотеки могут быть сломаны, что плохо. Я был укушен проблемами с этим материалом перед разделяемыми библиотеками; обычно слабые символы разрешаются при конечном времени соединения и больше не могут быть объединены при динамическом времени связи. Stick со статическими библиотеками или вообще не использовать статические элементы в типах шаблонов. – bdonlan

0

Хотя я может неправильно понять ваш вопрос, если хранения в вашем вопросе означает определения, мой ответ мог бы применить.
Как для одного правила определения, 3.2 p5 стандарта говорит:

Там может быть более чем одно определением из ... статического члена данных шаблона класса ... в программе при условии, что каждое определение появляется в другом ЕП,

и

Если определения D удовлетворить всеэти требования, то программа должны вести себя, как если бы один определения D.

Есть некоторые требования к этому правилу. В этом вопросе , так как переменная , инициализированная интегральной константой 0, удовлетворяет требованиям.