在某些主对象的析构函数中在堆栈上创建一个worker-object并将master-object的this
指针传递给helper-object是合法的C ++吗?然后,辅助对象还将调用主对象的成员函数或访问成员变量。
换句话说,以下是合法的C ++吗?
struct MasterClass
{
MasterClass (int data);
~MasterClass ();
int data;
};
struct WorkerClass
{
WorkerClass (MasterClass *m) : m (m) { }
void do_some_work () { m->data = 42; }
MasterClass *m;
};
MasterClass::MasterClass (int data)
: data (data)
{ }
MasterClass::~MasterClass ()
{
WorkerClass w (this);
w.do_some_work ();
}
int main ()
{
MasterClass m (7);
}
据我所知,一旦析构函数开始执行,master-object的生命周期就会结束。但我认为在任何对象的析构函数中调用非虚拟成员函数是合法的,这些函数使用隐式this
参数/参数。
答案 0 :(得分:7)
是和否。
是的,因为你在这个非常简短的例子中显示了它的合法性。
不,因为它可能导致UB,在销毁期间有一些关于对象使用的警告
TLDR如果你没有任何继承,那总是很好。
现在,对于不的情况,在销毁期间使用对象。
以下情况将假设已经编写了以下内容
struct V;
struct A;
struct B;
struct D;
void foo(A* a = nullptr);
struct V {
virtual void f();
virtual void g();
};
struct A : virtual V {
virtual void f();
};
struct B : virtual V {
virtual void g();
~B() {
foo();
}
};
struct D : A, B {
virtual void f();
virtual void g();
~D() {
foo(this);
}
};
int main() {
D d;
}
x
的破坏(又称破坏者被召唤)
如果虚函数调用使用显式类成员访问,并且对象表达式引用
x
的完整对象或该对象的基类子对象之一但不是x
或其基类之一子对象,行为未定义。
这意味着,如果您使用显式类成员访问来调用指向整个x
的指针的虚函数,但不知何故,指针不是x
的类型,也不是基础,行为是不确定的。
void foo(A* a) {
static auto ptr = a;
ptr->g(); // UB when called from ~B
// ptr refers to B, but is neither B nor its base
}
typeid
如果
typeid
的操作数引用正在构造或销毁的对象,并且操作数的静态类型既不是构造函数或析构函数的类,也不是其基础之一,则行为是未定义的。
同样,如果操作数引用被破坏的对象,但不知何故不是对象及其基础,则行为未定义。
void foo(A* a) {
static auto ptr = a;
typeid(*ptr); // UB when called from ~B()
// ptr refers to B, but is neither B nor its base
}
dynamic_cast
如果
dynamic_cast
的操作数引用正在构造或销毁的对象,并且操作数的静态类型不是构造函数或析构函数自己的类或其基础之一的指针或对象,{ {1}}导致未定义的行为。
同样的交易。
dynamic_cast
现在,如果你认为这是一场惨败并且不明白发生了什么,那就不要在析构函数中的任何地方传递void foo(A* a) {
static auto ptr = a;
dynamic_cast<B*>(ptr); // UB when called from ~B()
// ptr refers to B, but is neither B nor its base
}
。
答案 1 :(得分:1)
是的,这是合法的,因为在终止执行析构函数之前不会销毁主对象。
然而,这并不是一般的好习惯。