在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 ++对象会自行清理。
答案 0 :(得分:0)
[basic.start.init] / 2 :如果程序启动了线程(30.3),则变量的后续初始化相对于在不同转换中定义的变量的初始化是不排序的单元。否则,相对于在不同翻译单元中定义的变量的初始化,不确定地对变量进行初始化。如果程序启动线程,则相对于所有其他动态初始化,变量的后续无序初始化是无序列的。否则,相对于所有其他动态初始化,变量的无序初始化将不确定地排序。
(强调我的。)因此,只要您不在任何静态对象的构造函数中启动线程,就可以保证与标准的早期版本中的线程相同。