Как выполнить статическую деинициализацию, если деструктор имеет побочные эффекты и доступ к объекту осуществляется из деструктора другого статического объекта? - PullRequest
4 голосов
/ 29 июня 2010

Существует простой и хорошо известный шаблон, позволяющий избежать статического сбоя при инициализации, который описан в разделе раздела 10.13 C ++ FAQ Lite .

В этом стандартном шаблоне есть торговля-off сделано так, что либо построенный объект никогда не будет разрушен (что не является проблемой, если деструктор не имеет важных побочных эффектов), либо к статическому объекту нельзя безопасно получить доступ из деструктора другого статического объекта (см. раздел 10.14 изC ++ FAQ Lite ).

Итак, мой вопрос: как избежать фиаско деинициализации статического кода, если деструктор статического объекта имеет важные побочные эффекты, которые в конечном итоге должны произойти и к статическому объекту должен обращаться другой деструктор статического объекта?


(Примечание: в FAQ-литературе упоминается, что на этот вопрос дан ответ в FAQ 16.17 из C ++ FAQs: Часто задаваемые вопросы М. Клайном и Г. Ломоу. У меня нет доступа к этой книге, поэтому я задаю этот вопрос ввместо него.)

Ответы [ 3 ]

4 голосов
/ 29 июня 2010

функция статических объектов, таких как глобальные объекты, гарантированно будет уничтожена (при условии, что они созданы).

Порядок уничтожения является обратным созданию.
Таким образом, если объект зависит от другого объекта во время уничтоженияВы должны гарантировать, что это все еще доступно.Это относительно просто, так как вы можете форсировать порядок уничтожения, убедившись, что порядок создания выполнен правильно.

Следующая ссылка о одиночных кнопках, но описывает похожую ситуацию и ее решение:
Поиск проблем порядка статической инициализации в C ++

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

namespace B
{
    class B { ... };

    B& getInstance_Bglob;
    {
        static B instance_Bglob;
        return instance_Bglob;;
    }

    B::~B()
    {
         A::getInstance_abc().doSomthing();
         // The object abc is accessed from the destructor.
         // Potential problem.
         // You must guarantee that abc is destroyed after this object.
         // To gurantee this you must make sure it is constructed first.
         // To do this just access the object from the constructor.
    }

    B::B()
    {
        A::getInstance_abc();
        // abc is now fully constructed.
        // This means it was constructed before this object.
        // This means it will be destroyed after this object.
        // This means it is safe to use from the destructor.
    }
}
namespace A
{
    class A { ... };

    A& getInstance_abc()
    {
        static A instance_abc;
        return instance_abc;
    }
}
0 голосов
/ 29 июня 2010

Это что-то вроде хака, но я бы добавил несколько статических bools для отслеживания порядка деинициализации. Затем объект, который заканчивается последним, выполняет очистку, даже если он не является владельцем.

0 голосов
/ 29 июня 2010

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

Если вам нужно, чтобы это происходило между единицами компиляции, вам не повезло. Лучше создавать их динамически во время выполнения и уничтожать их в конце main, а не делать их статичными.

...