Здраствуйте. Помогите разобраться со следующим вопросом:
Имеет место быть такая конструкция:
//...
template <TObject>
class foo{
//...
static std::deque<TObject> TObjectMas;
public:
foo(){}
~foo(){
// что то делаем
}
};
//...
template<> std::deque<TSerialObject * > foo<TSerialObject> TObjectMas;
//....
// где-то в программе
class client{
//...
foo<TSerialOblect * > f;
public:
client(){}
~client(){}
};
//...
При инициализации главной формы (проект на C++ Builder) в её конструкторе
делаем так:
client * c=new client;
Вопрос: Почему при закрытии приложения когда мы добираемся до деструктора
foo::~foo(){} деструктор ~deque уже был вызван и удалил очередь вместе со всем содержимым?
Заранее благодарен за ответы(любые) и извините за сумбурное изложение.
wdm>//... wdm>При инициализации главной формы (проект на C++ Builder) в её конструкторе wdm>делаем так: wdm>client * c=new client; wdm>Вопрос: Почему при закрытии приложения когда мы добираемся до деструктора wdm>foo::~foo(){} деструктор ~deque уже был вызван и удалил очередь вместе со всем содержимым?
Не понятно в какой момент ты делал delete c;, но возможно, что уже после того, как начала отрабатываться уничтожение глобальных переменных. Т.е. вызов кода из деструктора статического экземпляра класса (см ниже) может привести к такому результату
class Temp
{
~Temp()
{
delete c; // часть статических переменных уже была уничтожена
}
};
Temp temp;
Здравствуйте, wdm, Вы писали:
wdm>При инициализации главной формы (проект на C++ Builder) в её конструкторе wdm>делаем так: wdm>client * c=new client; wdm>Вопрос: Почему при закрытии приложения когда мы добираемся до деструктора wdm>foo::~foo(){} деструктор ~deque уже был вызван и удалил очередь вместе со всем содержимым?
Кто это "мы"? Не понятно, когда ты вызываешь delete c;. приведи кусочек кода.
A>Не понятно в какой момент ты делал delete c;, но возможно, что уже после того, как начала отрабатываться уничтожение глобальных переменных. Т.е. вызов кода из деструктора статического экземпляра класса (см ниже) может привести к такому результату
Деструктор с я вызываю из деструктора главной формы соответственно. Когда писал вопрос я это упустил, извините.
Что касается удаления статических переменных то вопрос можно юыло бы переформулировать след. образом — как управлять последовательностью их уничтожения.
Раньше я делал так:
Здравствуйте, Glоbus, Вы писали:
wdm>>При инициализации главной формы (проект на C++ Builder) в её конструкторе wdm>>делаем так: wdm>>client * c=new client; wdm>>Вопрос: Почему при закрытии приложения когда мы добираемся до деструктора wdm>>foo::~foo(){} деструктор ~deque уже был вызван и удалил очередь вместе со всем содержимым?
G>Кто это "мы"? Не понятно, когда ты вызываешь delete c;. приведи кусочек кода.
Еще раз извиняюсь за неточность в вопросе. delete c вызываю естественно в деструкторе формы.
Здравствуйте, wdm, Вы писали:
wdm>Деструктор с я вызываю из деструктора главной формы соответственно. Когда писал вопрос я это упустил, извините. wdm>Что касается удаления статических переменных то вопрос можно юыло бы переформулировать след. образом — как управлять последовательностью их уничтожения.
По хорошему никак. Единственный принцип, то, что было инициализировано первым, будет уничтожено последним.
wdm>и все работало на ура. Но сейчас даже такой прием не помогает. Обьясните дураку как правильно?
Можно сделать так:
template<typename T> class foo
{
public:
// как-бы Singleton, работает только в однопоточной средеstatic std::deque<T>*& deque_ptr_() const
{
static std::deque<T>* pointer;
return pointer;
}
// образаться к deque при помощи этой функцииstatic std::deque<T>& get_deque()
{
if (!deque_ptr_())
{
deque_ptr_()=new std::deque<>();
//atexit(&foo::destroy_deque);
// можно сделать так, но в твоем случае,
// это ничего не изменит, поскольку
// функция destroy_deque вызовется
// до удаления большинства статических
// переменных, и последующий вызов get_deque() из
// какого-либо деструктора приведет к зацикливанию
}
return *deque_ptr_();
}
// необходимо явно вызывать при завершении программы
// если раскоментировать atexit выше, то явное удаление не требуетсяstatic void __cdecl destroy_deque()
{
delete deque_ptr_();
deque_ptr_()=0;
}
foo() {}
~foo() {}
};
Здравствуйте, Alex_Avr, Вы писали:
A_A>Здравствуйте, wdm, Вы писали:
A_A>Хм, что-то я не понял, выделенное — это определение статической переменной класса? A_A>Мне кажется, что должно быть как-то так:
template<> — это частичная специализация
перед первым использованием статической переменной я должен её проинициализировать что бы под неё была выделене память
если сделать как у тебя подо что память выделяться то будет? тип TObject то не известно что такое.
а тип TSerialObject определен и никаких проблем нет.
Здравствуйте, wdm, Вы писали:
wdm>template<> — это частичная специализация wdm>перед первым использованием статической переменной я должен её проинициализировать что бы под неё была выделене память wdm>если сделать как у тебя подо что память выделяться то будет? тип TObject то не известно что такое. wdm>а тип TSerialObject определен и никаких проблем нет
обратите внимание, что если объявлять вместо статической переменной шаблона класса статическую переменную функции, как сделано здесь
Здравствуйте, Aera, Вы писали:
A>обратите внимание, что если объявлять вместо статической переменной шаблона класса статическую переменную функции, как сделано здесь
, то объявлять ничего не нужно и необходимая переменная сама создается при инстацировании класса.
Хм, не могли бы вы по подробнее разъяснить что происходит в таком случае?
Откровенно говоря для меня подобная конструкция кажется несколько не привычной...не сталкивался как-то....
Здравствуйте, wdm, Вы писали:
wdm>Хм, не могли бы вы по подробнее разъяснить что происходит в таком случае? wdm>Откровенно говоря для меня подобная конструкция кажется несколько не привычной...не сталкивался как-то....
template<typename T> class foo
{
public:
// как-бы Singleton, работает только в однопоточной средеstatic std::deque<T>*& deque_ptr_()
{
static std::deque<T>* pointer;
return pointer;
}
// образаться к deque при помощи этой функцииstatic std::deque<T>& get_deque()
{
if (!deque_ptr_())
{
deque_ptr_()=new std::deque<>();
//atexit(&foo::destroy_deque);
// можно сделать так, но в твоем случае,
// это ничего не изменит, поскольку
// функция destroy_deque вызовется
// до удаления большинства статических
// переменных, и последующий вызов get_deque() из
// какого-либо деструктора приведет к зацикливанию
}
return *deque_ptr_();
}
// необходимо явно вызывать при завершении программы
// если раскоментировать atexit выше, то явное удаление не требуетсяstatic void __cdecl destroy_deque()
{
delete deque_ptr_();
deque_ptr_()=0;
}
foo() {}
~foo() {}
};
Если мы инстацируем класс например foo<int>, то создается функция foo<int>::deque_ptr_() в которой есть статическая переменная pointer. Компилятор автоматически отводит под нее место для каждого типа T. Что-то типа этого:
std::deque<int>* foo<int>::deque_ptr_::pointer=0;
Для того, чтобы управлять временем удаления переменной, создаем не статический эземпляр, а указатель на него. Обращаемся к deque посредством функции get_deque(), что позволяет при первом запуске инициализировать указатель.
Здравствуйте, wdm, Вы писали:
A_A>>template<class TObject> A_A>>std::deque<TObject> foo<TObject>::TObjectMas; wdm>[/code]
wdm>template<> — это частичная специализация wdm>перед первым использованием статической переменной я должен её проинициализировать что бы под неё была выделене память wdm>если сделать как у тебя подо что память выделяться то будет? тип TObject то не известно что такое. wdm>а тип TSerialObject определен и никаких проблем нет.
Насколько я знаю, память под статическую переменную шаблонного класса выделяется компилятором
при инстанцировании шаблона для конкретного типа, т.е. в твоем случае, когда ты объявляешь
//...
foo<TSerialObject *> f;
//...
Что касается синтаксиса объявления статической переменной шаблонного класса, то вот что
говорит по этому поводу стандарт (2003):
14.5.1.3 Static data members of class templates
A definition for a static data member may be provided in a namespace scope enclosing the definition of the
static member’s class template.
[Example:
template<class T> class X {
static T s;
};
template<class T> T X<T>::s = 0;
—end example]
У меня, во всяком случае, приведенный мной пример успешно откомпилировался на VC 7.1 и никаких
проблем с деструктором при его выполнении не возникло.