在析构函数中将 "this" 指针传递给其他 class/function
Passing the "this" pointer to other class/function in destructor
C++ 在一些主对象的析构函数中在堆栈上创建一个工作对象并将主对象的 this
指针传递给辅助对象是否合法?然后,辅助对象还将调用主对象的成员函数或访问成员变量。
也就是说,下面的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);
}
我知道一旦析构函数开始执行,主对象的生命周期就结束了。但我相信在任何对象的析构函数中调用非虚拟成员函数是合法的,它使用隐式 this
argument/parameter.
是的,这是合法的,因为主对象不会在析构函数执行终止之前被销毁。
但是,这通常不是一个好的做法。
是也不是。
是的,因为在您展示的这个非常短的示例中它是合法的。
不,因为它可能会导致 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
销毁时(也就是调用其析构函数时)
If the virtual function call uses an explicit class member access and the object expression refers to the complete object of x
or one of that object's base class subobjects but not x
or one of its base class subobjects, the behavior is undefined.
这意味着,如果您使用显式 class 成员访问来调用一个指针指向整个 x
的虚函数,但指针不是 x
的类型=14=] 也不是它的基础,行为是未定义的。
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
If the operand of typeid
refers to the object under construction or destruction and the static type of the operand is neither the constructor or destructor's class nor one of its bases, the behavior is undefined.
同样,如果操作数指的是被析构的对象,但不知何故不是对象及其基类,则行为未定义。
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
If the operand of the dynamic_cast
refers to the object under construction or destruction and the static type of the operand is not a pointer to or object of the constructor or destructor's own class or one of its bases, the dynamic_cast
results in undefined behavior.
同样的交易。
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
}
结论
现在,如果您认为这是一场惨败并且不明白发生了什么,那就不要在析构函数中的任何地方传递 this
。
C++ 在一些主对象的析构函数中在堆栈上创建一个工作对象并将主对象的 this
指针传递给辅助对象是否合法?然后,辅助对象还将调用主对象的成员函数或访问成员变量。
也就是说,下面的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);
}
我知道一旦析构函数开始执行,主对象的生命周期就结束了。但我相信在任何对象的析构函数中调用非虚拟成员函数是合法的,它使用隐式 this
argument/parameter.
是的,这是合法的,因为主对象不会在析构函数执行终止之前被销毁。
但是,这通常不是一个好的做法。
是也不是。
是的,因为在您展示的这个非常短的示例中它是合法的。
不,因为它可能会导致 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
销毁时(也就是调用其析构函数时)
If the virtual function call uses an explicit class member access and the object expression refers to the complete object of
x
or one of that object's base class subobjects but notx
or one of its base class subobjects, the behavior is undefined.
这意味着,如果您使用显式 class 成员访问来调用一个指针指向整个 x
的虚函数,但指针不是 x
的类型=14=] 也不是它的基础,行为是未定义的。
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
If the operand of
typeid
refers to the object under construction or destruction and the static type of the operand is neither the constructor or destructor's class nor one of its bases, the behavior is undefined.
同样,如果操作数指的是被析构的对象,但不知何故不是对象及其基类,则行为未定义。
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
If the operand of the
dynamic_cast
refers to the object under construction or destruction and the static type of the operand is not a pointer to or object of the constructor or destructor's own class or one of its bases, thedynamic_cast
results in undefined behavior.
同样的交易。
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
}
结论
现在,如果您认为这是一场惨败并且不明白发生了什么,那就不要在析构函数中的任何地方传递 this
。