假设我有两个C++类:
class A
{
public:
A() { fn(); }
virtual void fn() { _n = 1; }
int getn() { return _n; }
protected:
int _n;
};
class B : public A
{
public:
B() : A() {}
virtual void fn() { _n = 2; }
};
Run Code Online (Sandbox Code Playgroud)
如果我写下面的代码:
int main()
{
B b;
int n = b.getn();
}
Run Code Online (Sandbox Code Playgroud)
人们可能期望将n其设置为2.
事实证明,n设置为1.为什么?
请考虑以下示例:
#include <csignal>
class A
{
public:
virtual ~A() {}
virtual void foo() = 0;
};
class B : public A
{
public:
virtual ~B() { throw 5; }
virtual void foo() {}
};
int main(int, char * [])
{
A * b = new B();
try
{
delete b;
}
catch ( ... )
{
raise(SIGTRAP);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我一直认为(天真的我),当程序在这种情况下获得,进入catch部分,则对象B在这b点将会保留,因为它是相当合乎逻辑的例外,将有"取消"(如果编程安全)的析构函数的效果.但是当我试图在gdb中运行这个片段并且在catch部分中找到断点时,我看到B对象已经消失,只剩下一个基础对象,因为vtable看起来像这样:
(gdb) i vtbl b
vtable for 'A' @ 0x400cf0 (subobject …Run Code Online (Sandbox Code Playgroud) 在析构函数的最后一行,我有一个诊断类型消息,它采用类似printf形式:
"object destroyed at %p", this
Run Code Online (Sandbox Code Playgroud)
我担心this在这一点上如何定义.
我应该预约吗?行为定义明确吗?
假设您有一个可以被多个线程访问的对象。临界区用于保护敏感区域。但是析构函数呢?即使我一进入析构函数就进入临界区,一旦调用了析构函数,对象是否已经失效了?
我的思路:假设我进入了析构函数,我必须等待临界区,因为其他线程仍在使用它。一旦他完成,我就可以完成破坏对象。这有意义吗?
另一个问题引用了C++标准:
3.8/1 “类型 T 的对象的生命周期在以下情况下结束: — 如果 T 是具有非平凡析构函数的类类型 (12.4),则析构函数调用开始,或者 — 对象占用的存储空间被重用或释放。 ”
这似乎意味着不允许从析构函数访问对象的成员。然而,这似乎是错误的,事实更像是 Kerrek SB 的回答中所解释的:
成员对象在构造函数体运行之前活跃起来,并且它们一直活跃到析构函数完成之后。因此,您可以在构造函数和析构函数中引用成员对象。
对象本身直到它自己的构造函数完成后才会活跃起来,并且一旦它的析构函数开始执行它就会死亡。但这仅就外部世界而言。构造函数和析构函数仍然可以引用成员对象。
我想知道在析构函数中是否可以将对象的地址传递给外部类,例如:
struct Person;
struct Organizer
{
static void removeFromGuestList(const Person& person); // This then accesses Person members
}
struct Person
{
~Person() {
// I'm about to die, I won't make it to the party
Organizer::removeFromGuestList(*this);
}
};
Run Code Online (Sandbox Code Playgroud)
这对我来说似乎没问题,因为我认为对象的生命周期一直持续到析构函数完成之后,但是上述答案的这一部分让我怀疑:
对象本身直到它自己的构造函数完成后才会活跃起来,并且一旦它的析构函数开始执行它就会死亡。但这仅就外部世界而言。构造函数和析构函数仍然可以引用成员对象。