Статические члены уничтожаются, пока есть еще выдающиеся экземпляры? - PullRequest
3 голосов
/ 10 мая 2011

Мне нужен доступ к статическому члену данных из деструктора, но при выходе из программы кажется, что он не может быть гарантированно по-прежнему существовать!По какой-то причине статические члены уничтожаются, в то время как все еще существуют выдающиеся экземпляры класса.Это странно, потому что я никогда не слышал совета «Никогда не получай доступ к статическим элементам из деструктора» раньше, и все же я думаю, что я знал бы о таком ограничении, если бы оно существовало.

Я приведу конкретный пример:

class MyClass {
    public:
        ~MyClass() { m_instances.erase(m_name); }

    private:
        long m_name;
        static std::map<long, MyClass*> m_instances;
};

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

class MyClass {
    friend class Switch;

    public:
        ~MyClass() { if (m_alive) m_instances.erase(m_name); }

    private:

        static bool m_alive;
        class Switch {
            ~Switch() { MyClass::m_alive = false; }
        };
        static Switch m_switch;

        long m_name;
        static std::map<long, MyClass*> m_instances;
};

Что если экземпляр MyClass будет уничтожен после m_instances, но до m_switch ??И даже если m_switch умрет первым, логическое значение m_alive могло быть «уничтожено» и, следовательно, возможно, перезаписано на «true» (маловероятно, я знаю).

Так может ли кто-нибудь предложить лучшее решение?Я ожидаю, что упускаю что-то очень очевидное здесь.

Ответы [ 3 ]

2 голосов
/ 10 мая 2011

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

При рассмотрении срока службы рассмотрите ваши статические элементы как любой другой статический объект. В действительности нет ничего связывающего их с содержащим их классом, кроме как в «пространстве имен» класса ( предупреждение: не точная терминология ).

Итак, если ваши myClass экземпляры тоже создаются статически, то вам необходимо учитывать нормальные правила жизни статических объектов между ними:

Пример # 1 :

#include <iostream>

struct A {
    A() { std::cout << "*A "; };
   ~A() { std::cout << "~A "; };
};

struct B {
    B() { std::cout << "*B "; };
   ~B() { std::cout << "~B "; };

    static A a;
};

B t;
A B::a;

int main() {}

// Output: *B *A ~A ~B 

Как видите, статический член B уничтожен до фактического экземпляра B.

Пример № 2:

#include <iostream>

struct A {
    A() { std::cout << "*A "; };
   ~A() { std::cout << "~A "; };
};

struct B {
    B() { std::cout << "*B "; };
   ~B() { std::cout << "~B "; };

    static A a;
};

A B::a;
B t;

int main() {}

// Output: *A *B ~B ~A 

Здесь верно обратное. Это дешевое решение для вашей текущей проблемы, но я советую вообще избегать статических случаев; вы только попадете в более статичные ловушки инициализации, подобные этой, в будущем ... возможно, в будущем воплощении того же кода!

2 голосов
/ 10 мая 2011

Это явно проблема порядка статического разрушения.Я бы порекомендовал что-то вроде следующего:

class MyClass {
    public:
        MyClass() { add_instance(m_name, this); };
        ~MyClass() { erase_instance(m_name); }

    private:
        long m_name;
        static std::map<long, MyClass*>& get_instance_map();
        static void add_instance(long aName, MyClass* aObj);
        static void erase_instance(long aName);
};

std::map<long, MyClass*>* MyClass::get_instance_map() {
  static std::map<long, MyClass*>* p_inst = new std::map<long, MyClass*>();
  return p_inst;
};

void MyClass::add_instance(long aName, MyClass* aObj) {
  static std::map<long, MyClass*>* p_inst = MyClass::get_instance_map();
  p_inst->insert( std::make_pair(aName, aObj) );
};

void MyClass::erase_instance(long aName) {
  static std::map<long, MyClass*>* p_inst = MyClass::get_instance_map();
  p_inst->erase( aName );
};

Если вам нужно удалить карту экземпляра, это может быть невозможно.В противном случае просто используйте нормальную конструкцию при первом использовании.Дело в том, что карта представляет собой выделенный в куче объект std :: map, и ее удаление не означает, что она будет удалена, поскольку ОС освобождает память для свободного восстановления, которая будет появляться после каждого другого «нормального» выполнения, напримервызов деструктора.

0 голосов
/ 10 мая 2011

Если вы сталкиваетесь с подобными проблемами со статическими объектами, это должно означать, что MyClass также имеет статическую область видимости, и вы не можете создать подобный код, когда один статический элемент обращается к другому. Это может сработать и не сработать, поскольку у вас есть проблема с порядком уничтожения.

Также вполне возможно, что у вас есть другая глобальная (статическая) причина повреждения памяти. Если это так, это может означать, что перезапись одного глобального объекта может перезаписать другой глобальный объект, находящийся в том же пространстве памяти, т. Е. Статический файл, с которым у вас возникли проблемы, поврежден и не удален.

...