C++ 在构造函数完成之前调用析构函数是否合法?
假设我有一个类,其构造函数生成一个删除该对象的线程:C++ 在构造函数完成之前调用析构函数是否合法?,c++,asynchronous,constructor,destructor,C++,Asynchronous,Constructor,Destructor,假设我有一个类,其构造函数生成一个删除该对象的线程: class foo { public: foo() : // initialize other data-members , t(std::bind(&foo::self_destruct, this)) {} private: // other data-members std::thread t; // no more data-members declared aft
class foo {
public:
foo()
: // initialize other data-members
, t(std::bind(&foo::self_destruct, this))
{}
private:
// other data-members
std::thread t;
// no more data-members declared after this
void self_destruct() {
// do some work, possibly involving other data-members
delete this;
}
};
这里的问题是析构函数可能在构造函数完成之前被调用。这个案子合法吗?由于t
是最后声明(并因此初始化)的,并且构造函数体中没有代码,而且我从来没有打算对这个类进行子类化,因此我假设在调用self_destruct
时对象已经完全初始化。这个假设正确吗
我知道声明删除了这个如果在该语句之后未使用此
,则代码>在成员函数中是合法的。但构造函数在几个方面都很特殊,所以我不确定这是否有效
此外,如果它是非法的,我不知道如何处理它,其他的在一个特殊的初始化函数中生成线程,必须在对象构造之后调用,这是我真正想要避免的
附言:我正在寻找C++03的答案(这个项目我只限于使用较旧的编译器)。示例中的
std::thread
仅用于说明目的。删除此项代码>在大多数平台上都能正常工作;有些甚至可以作为特定于平台的扩展来保证正确的行为。但根据标准,IIRC并没有很好的定义
您所依赖的行为是,通常可以在死对象上调用非虚拟非静态成员函数,只要该成员函数没有实际访问此
。但这种行为是标准所不允许的;它充其量是不可携带的
本标准第3.8p6节规定,如果对象在调用非静态成员函数期间不活动,则为未定义行为:
类似地,在对象的生存期开始之前,但在分配对象将占用的存储之后,或者在对象的生存期结束之后,在重用或释放对象占用的存储之前,可以使用引用原始对象的任何glvalue,但只能以有限的方式使用。对于正在建造或破坏的物体,见12.7。否则,这样的值是指分配的
存储,并使用不依赖于其值的glvalue的属性是定义良好的。在以下情况下,程序具有未定义的行为:
- 将左值到右值的转换应用于这样的值
- glvalue用于访问非静态数据成员或调用对象的非静态成员函数,或
- glvalue隐式转换为对基类类型的引用,或
- glvalue用作
的操作数,除非最终完成转换 到静态_cast
cv
或char&
cv
,或无符号char&
- glvalue用作
的操作数或动态\u cast
的操作数类型ID
对于这种特殊情况(删除正在施工的对象),我们在第5.3.5p2节中发现: 。。。在第一个备选方案(删除对象)中,
delete
的操作数值可以是空指针值、指向由以前的新表达式创建的非数组对象的指针,或者指向表示此类对象基类的子对象的指针(第10条)。如果不是,则行为未定义。在第二种选择(删除数组)中,delete
的操作数的值可以是空指针值,也可以是由以前的数组新表达式生成的指针值。如果不是,则行为未定义
这项要求没有得到满足<代码>*此不是由新表达式创建的过去时对象。它是正在创建的对象(当前进行)。数组案例支持这种解释,其中指针必须是先前新表达式的结果。。。但新表达式尚未完全评估;首先,我们看到类型为
foo
的对象具有非平凡的初始化,因为它的构造函数是非平凡的(§3.8/1):
如果一个对象属于类或聚合类型,并且它或它的一个成员是由一个构造函数而不是一个普通的默认构造函数初始化的,则称该对象具有非普通的初始化
现在我们看到foo
类型的对象的生命周期在构造函数结束后开始(§3.8/1):
类型为T
的对象的生存期始于:
- 获得T型的适当对齐和尺寸的存储,以及
- 如果对象具有非平凡的初始化,则其初始化已完成
foo
具有非平凡析构函数(§3.8/5),则在构造函数结束之前对对象执行delete
,这是未定义的行为:
在对象的生存期开始之前,但在分配对象将占用的存储之后[…]可以使用指向对象将要或曾经所在的存储位置的任何指针,但只能以有限的方式使用。对于正在建造或破坏的物体,见12.7。否则,[……]
因此,由于我们的目标正在建设中,我们来看一下§12.7:
构件函数,包括虚拟函数(10.3),可在构造或销毁过程中调用(12.6.2)
这意味着,在构建对象时调用自毁
是可以的。然而,本节并没有特别提到在构建对象时销毁对象。因此,我建议我们看看delete表达式的操作
首先,它“将为要删除的对象[…]调用析构函数(如果有)。”析构函数是成员函数的特例,因此可以调用它。但是,§12.4 D