在以下代码中,X在全局容器中注册,该容器成为其共享所有者.X的析构函数测试它不再是这种所有权的一部分了,我希望它是被破坏的有效前提条件.
#include <vector>
#include <memory>
struct X {
~X();
};
std::vector<std::shared_ptr<X> > global_x_reg;
X::~X()
{
for (auto iter = global_x_reg.begin(), end = global_x_reg.end(); iter != end; ++iter)
if (iter->get() == this)
throw "Oops. X gets destroyed while it is still owned!";
}
int main(int argc, char** argv)
{
global_x_reg.push_back( std::shared_ptr<X>(new X) );
global_x_reg.clear(); // calls X::~X().
}
Run Code Online (Sandbox Code Playgroud)
当它运行时(在使用VS2010编译之后),当清除容器时抛出"Oops ...".
问题:
clear()以这样的方式实现,即在其值的破坏期间,这些值不再作为容器可见. std::shared_ptr::get在什么时候std::shared_ptr摧毁它的指针nullptr呢?根据 N3936 [basic.life]/1:“具有重要初始化的对象的生命周期在析构函数调用开始时结束。”和/3:
\n\n\n\n\n本国际标准中赋予对象的属性仅适用于给定对象的生命周期。[注意:特别是,在对象的生命周期开始之前和其生命周期结束之后,对象的使用存在显着的限制,如下所述,在 12.6.2 和 12.7 中。此外,正在构造和销毁的对象的行为可能与生命周期已开始但尚未结束的对象的行为不同。12.6.2 和 12.7 描述了对象在构建和销毁阶段的行为。\xe2\x80\x94尾注]
\n
shared_ptr您在 a的生命周期结束后调用该成员函数。由于无法知道给定的标准库类成员函数是否符合指定的限制,因此在其生命周期结束后调用标准库对象上的成员函数会产生未定义的行为,除非另有指定。
另请参阅库工作组第 2382 期“删除对象时容器更新与对象销毁的顺序不明确”,这与该问题非常相关。global_x_reg一般来说,当标准库对象 ( ) 正在处理成员函数调用时(在本例中) ,重新输入它并不是一个好主意global_x_reg.clear()。显然,类不变量必须在成员调用之前和之后保持不变,但不能保证对象在调用期间处于有效状态。