【发布时间】:2019-03-17 05:29:17
【问题描述】:
在 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++ 对象会自行清理。
【问题讨论】:
-
我猜“避免静态”不是一个可以接受的答案...... :)
-
您需要注册的对象是否可以有一个包含 shared_ptr 的附加成员...例如,取消注册单例?然后 shared_ptr 语义将控制注销对象的生命周期。那应该安全吗?
-
另外,如果你确实需要一个同步原语,你可以用原子构建一个 - 或者可能已经有一个 - 因为它实际上并没有被破坏,所以可以安全地以任何顺序使用......
标签: c++11 destructor exit