Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > GNU toolchain > статические переменные


Автор: mes 17.6.2008, 11:36
недавно столкнулся с одной загадкой в двух проявлениях :
1.
Код
 // a.cpp
А& GetA () { static A a; return a; }  
- при вызове этой функции из деструктора главной формы (используется библиотека wxWigdets, но по идеи не суть важно) возврашалась невалидная ссылка - статический обьект был разрушен хотя мы еше в цикле main. 

2. 
Код

class W { 
     typedef  std::map<std::string, W*> WMap;
     static WMap& GetWMap () { static WMap map; return map; } 
    }; 
 - также возврашалась невалидная ссылка, (вызов был инициирован из функции другого класса) несмотря на то что статическая переменная спрятаная в функцию  - однако перенос тела функции в .cpp исправил ситуацию.

Обе описанные ситуации были получены на компиляторе MinGW (других не пробовал)  
но установленные на разных компах давали разные результаты (скачивались с одного и того же сайта но в разное время - так что вполне могут быть разные по обновлению)

Вопрос:  как тогда правильно использовать функции возврашаюшиее ссылки на статические обьекты, чтоб избежать такого непредсказуемого поведения
Заранее спасибо.

     



Автор: Alek86 17.6.2008, 11:50
Код

class W { 
     typedef  std::map<std::string, W*> WMap;
     static WMap& GetWMap () { static WMap map; return map; } 
    }; 


есди этот код был в ашнике, то можент быть, создавались 2 реализацции функции GetWMap, и, соответственно, 2 статические переменные?

Автор: Lazin 17.6.2008, 12:08
я понял что имеет место что-то вроде этого  smile :
Код

class A
{
    B& get()
    {
        static B b;
        return b;
    }
};

namespace {
    A static_a;
}

class Form
{
    ...
    ~Form()
    {
        B& = static_a.get();
    }
};

Form form(...);

int main()
{
    .....
}

ошибка может возникнуть из-за того, что порядок создания переменных не определен, если сначала создан объект form, потом static_a, ну а потом static B b;, то удаляться они будут в обратном порядке..

Автор: UnrealMan 17.6.2008, 12:29
Цитата(mes @  17.6.2008,  11:36 Найти цитируемый пост)
Вопрос:  как тогда правильно использовать функции возврашаюшиее ссылки на статические обьекты, чтоб избежать такого непредсказуемого поведения

В программе, где не допускается undefined behavior (легко сказать smile). Не исключено, что источником проблем служит участок кода, который с виду никак не должен сказываться на этих статических объектах.

Цитата(Alek86 @  17.6.2008,  11:50 Найти цитируемый пост)
есди этот код был в ашнике, то можент быть, создавались 2 реализацции функции GetWMap, и, соответственно, 2 статические переменные? 

С какой стати?


Автор: mes 17.6.2008, 12:31
Цитата(Alek86 @  17.6.2008,  11:50 Найти цитируемый пост)
создавались 2 реализацции функции GetWMap, и, соответственно, 2 статические переменные? 

нет.. двух перемнных  не создавалось - возврашалась невалидная ссылка 


Цитата(Lazin @  17.6.2008,  12:08 Найти цитируемый пост)
я понял что имеет место что-то вроде этого 
Код

namespace {
    A static_a;
}
  

нет.. открытых ( не обернутых в функцию) не было

весь код выглядит примерно так:
Код


 // a.cpp
А& GetA () { static A a; return a; }  
//a.h
class A
{
   void  func() {} // пустая функция тоже провоцирует вылет
}
А& GetA () ;

//wchild.h

class WChild { 
     typedef  std::map<std::string, WChild*> WMap;
     static WMap& GetWMap () { static WMap map; return map; } 
  public:
     static WChild *  GetWChild (const std::string& name) { WMap::iterator it = GetWMap().find(name);
                                                                                             return (it!=GetWMap().end())? it->second : NULL;
                                                                                           } 
    }; 

// wform.cpp
void OnClose (..)
{
 GetA(). func (); // если вместо деструктора последний раз вызывать здесь , то вылета не происходит
}

WForm::WForm (..) : WFrame (..)
{
}

WForm::~WForm (..) 
{
   GetA(). func (); // вылетает (1й случай)
}

void WForm:: CreateChild (..)
{
   if (WChild::GetWChild(name)  // здесь вылетает по пункту 2.
       {..}
}




Добавлено @ 12:32
названния функций условны.. но места вызовов сохранены 

Автор: Alek86 17.6.2008, 12:35
Цитата(UnrealMan @  17.6.2008,  12:29 Найти цитируемый пост)
С какой стати?

я только предположил, ибо не знаю
к примеру из-за того, что каждый cpp компилится в свой obj
а как поступает компилер, когда видит код одной и той же функции в 2х cpp (и видит ли вообще) я не знаю. а может это вообще проблемы линковщика, подставить один и тот же адрес в 2 obj при их обработке

Автор: Lazin 17.6.2008, 12:41
Цитата(mes @  17.6.2008,  12:31 Найти цитируемый пост)
if (WChild::GetWChild(name)  // здесь вылетает по пункту 2.

возможно нет такого ключа... вот и вылетает 

может сделать WMap членом класса?

Автор: UnrealMan 17.6.2008, 12:42
Цитата(Alek86 @  17.6.2008,  12:35 Найти цитируемый пост)
а как поступает компилер, когда видит код одной и той же функции в 2х cpp (и видит ли вообще) я не знаю. а может это вообще проблемы линковщика, подставить один и тот же адрес в 2 obj при их обработке 

Это inline-функция, с ней должен разобраться линкер - он оставит только одну функцию, которая во всех единицах трансляции будет одной и той же. Но, в принципе, тут могут быть косяки, можно попробовать пересобрать весь проект.

Автор: Lazin 17.6.2008, 12:44
Цитата(mes @  17.6.2008,  12:31 Найти цитируемый пост)
WForm::~WForm (..) : WFrame (..)
{
   GetA(). func (); // вылетает (1й случай)
}

видимо вылитает при завершении программы, если да, то возможно из-за того, что статический объект
Цитата(mes @  17.6.2008,  12:31 Найти цитируемый пост)
А& GetA () { static A a; return a; }  

уже уничтожен...

в этом случае поможет синглтон...

Автор: UnrealMan 17.6.2008, 12:45
Ну, а вообще, конечно, следует использовать логи. Тогда можно быстро посмотреть, какие деструкторы когда вызываются.

Добавлено @ 12:46
Цитата(Lazin @  17.6.2008,  12:44 Найти цитируемый пост)
в этом случае поможет синглтон... 

Не всякий синглтон одинаково полезен.

Автор: Lazin 17.6.2008, 12:50
Цитата(UnrealMan @  17.6.2008,  12:45 Найти цитируемый пост)
Не всякий синглтон одинаково полезен.

использование одной статической переменной в деструкторе другой статической переменной ни разу не полезно smile 

Автор: mes 17.6.2008, 12:53
Цитата(Lazin @  17.6.2008,  12:44 Найти цитируемый пост)
А& GetA () { static A a; return a; }  


уже уничтожен...

в этом случае поможет синглтон... 


так в чем различие между  
Код

А& GetA () { static A a; return a; }  
и
class Singleton { 
public:
A& GetInstace ()  { static A a; return a; }  
};
 ?

Автор: Lazin 17.6.2008, 12:55
mes, поставь в деструктор класса A брейкпоинт и проверь, кто раньше удаляется...

Автор: UnrealMan 17.6.2008, 12:56
Цитата(Lazin @  17.6.2008,  12:50 Найти цитируемый пост)
использование одной статической переменной в деструкторе другой статической переменной ни разу не полезно 

У паттерна "синглтон" много реализаций. Синглтон Мейерса базируется на тех же статических переменных, и проблемы у него будут те же самые smile

Автор: mes 17.6.2008, 12:56
Цитата(Lazin @  17.6.2008,  12:50 Найти цитируемый пост)
использование одной статической переменной в деструкторе другой статической переменной ни разу не полезно   


само окно не является глобальным обэектом

Автор: Lazin 17.6.2008, 12:58
Цитата(mes @ 17.6.2008,  12:53)
Цитата(Lazin @  17.6.2008,  12:44 Найти цитируемый пост)
А& GetA () { static A a; return a; }  


уже уничтожен...

в этом случае поможет синглтон... 


так в чем различие между  
Код

А& GetA () { static A a; return a; }  
и
class Singleton { 
public:
A& GetInstace ()  { static A a; return a; }  
};
 ?

Код

class Singleton { 
    A* val;
    public:
    Singletone() : val (0) {}
    A& GetInstace ()  
    {
        if (val == 0)
            val = new A();
        return *val;            
    }  
};


Автор: DRUID3 17.6.2008, 12:58
Цитата(UnrealMan @  17.6.2008,  11:42 Найти цитируемый пост)
Это inline-функция, с ней должен разобраться линкер - он оставит только одну функцию, которая во всех единицах трансляции будет одной и той же. Но, в принципе, тут могут быть косяки, можно попробовать пересобрать весь проект. 

??? это как??? smile 

Автор: Lazin 17.6.2008, 12:59
разница в управлении временем жизни

Добавлено через 1 минуту и 28 секунд
Цитата(mes @  17.6.2008,  12:56 Найти цитируемый пост)
само окно не является глобальным обэектом 

из твоего кода, это было непонятно.

Автор: UnrealMan 17.6.2008, 13:06
Lazin, а кто будет вызывать delete? smile

Цитата(DRUID3 @  17.6.2008,  12:58 Найти цитируемый пост)
??? это как??? 

Что именно? Косяки с линковкой? Например, из-за путаницы с датировкой исходников. Может получиться так, что модифицированный исходник, который должен быть перекомпилирован, воспринимается как немодифицированный и в результате получаются не очень хорошие вещи.

Автор: Lazin 17.6.2008, 13:07
Цитата(UnrealMan @  17.6.2008,  13:06 Найти цитируемый пост)
а кто будет вызывать delete? smile 

а никто smile

Добавлено @ 13:20
можно еще сделать объект общим... 
Код

class Singleton 

    boost::shared_ptr<A> val;
public:
    Singletone() : val (0) {}
    boost::shared_ptr<A> GetInstace ()  
    {
        if (val == 0)
            val = boost::shared_ptr<A>(new A());
        return val;            
    }  
};

но это все уже из области домыслов smile 

Автор: mes 17.6.2008, 13:48
Попробую собрать картину воедино:
проблема 1 : возникала из за  неопределенного порядка удаления статических объектов..  
точнее из за того что деструктор формы вызывался за пределами main. 

проблема 2: появлась " благодаря " недосмотру линкеру
при использовании слова inline ситуация имела повторение на другом участке кода (с другой стат. переменной)

за активную помошь приведшую к пониманию и решению проблемы +1, для активных участников 

всем спасибо ))

Автор: mes 20.6.2008, 18:01
Цитата(Lazin @  17.6.2008,  12:58 Найти цитируемый пост)
Код

class Singleton { 
    A* val;
    public:
    Singletone() : val (0) {}
    A& GetInstace ()  
    {
        if (val == 0)
            val = new A();
        return *val;            
    }  
};
 


решил перечитать тему и наткнулся на этот код  - объясните, пожалуйста, с  какой такой стати класс приведенный выше является синглетном??

Автор: Lazin 23.6.2008, 10:36
Цитата(mes @  20.6.2008,  18:01 Найти цитируемый пост)
решил перечитать тему и наткнулся на этот код  - объясните, пожалуйста, с  какой такой стати класс приведенный выше является синглетном?? 

ну это просто создание экземпляра объекта по требованию

Код

Singletone& get_singletone()
{
    static Singleton value;
    return value;
}


A& value ( get().GetInstance() );


но вообще это написано в спешке и на коленке))

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)