Как я могу узнать, был ли статический объект уничтожен в C ++ 11 - PullRequest
0 голосов
/ 12 октября 2018

В спецификации C ++ 11, basic.start.term 1 заявляет:

Если завершение конструктора или динамическая инициализация объекта со статической продолжительностью хранения упорядочена раньше, чем у другогоЗавершение деструктора второго секвенируется до инициации деструктора первого.[Примечание: это определение допускает одновременное уничтожение.- конец примечания]

В C ++ 03 мои деструкторы были упорядочены.Заказ не может быть указан, но они были заказаны.Это было очень полезно для статических объектов, которые должны были регистрироваться сами.В спецификации не было концепции многопоточности, поэтому в спецификации не было неупорядоченных деструкторов.Компиляторы, которые реализовали многопоточность, о которой я знаю, уничтожали в однопоточной среде.

a.cpp:
  struct A
  {
       A()
       : mRegistration(0)
       { }

       ~A()
       {
           if (mRegistration)
             tryUnregisterObject(mRegistration);
       }

       void registerNow()
       {
           mRegistration = registerObject(this);
       }
  };

  A myA;

b.cpp:


  class Registrar
  {
      public:
           Registrar()
           {
               isAlive = true;
           }
           ~Registrar()
           {
               isAlive = false;
           }
      ...
  };

  bool isAlive = false; // constant initialization
  static Registrar& registrar()
  {
      static Registrar instance;
      return instance;
  }

  int registerObject(void* obj)
  {
      registar().register(obj);
  }

  void tryUnregisterObject(void* obj)
  {
     if (isAlive) {
        registrar().unregister(obj);
     } else {
        // do nothing.  registrar was destroyed
     }
  }

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

В C ++ 11 такой подход создает гонку данных вокруг переменной isAlive.Это может быть решено во время построения, потому что я могу создать объект синхронизации, такой как мьютекс, чтобы защитить его, когда он мне понадобится впервые.Однако в случае уничтожения мне, возможно, придется проверить isAlive после того, как мой мьютекс был уничтожен!

Есть ли способ обойти это в C ++ 11?Я чувствую, что мне нужен примитив синхронизации для решения проблемы, но все, что я пробовал, приводит к тому, что примитив будет уничтожен, прежде чем он будет готов, защищая то, что мне нужно защитить.Если бы я использовал потоковые примитивы Windows или PThreads, я мог бы просто не вызывать деструктор и позволить операционной системе очищаться после меня.Однако объекты C ++ очищаются.

1 Ответ

0 голосов
/ 12 октября 2018

[basic.start.init] / 2 Если программа запускает поток (30.3), последующая инициализация переменной не выполняется в последовательности с инициализацией переменной, определенной вдругой переводчик.В противном случае, инициализация переменной имеет неопределенную последовательность относительно инициализации переменной, определенной в другой единице перевода.Если программа запускает поток, последующая неупорядоченная инициализация переменной не секвенируется относительно любой другой динамической инициализации.В противном случае неупорядоченная инициализация переменной будет неопределенно упорядочена относительно любой другой динамической инициализации.

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

...