В спецификации 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 ++ очищаются.