假设我们有一个简单的结构:派生类的破坏后基类的使用成员
struct RefCounters {
size_t strong_cnt;
size_t weak_cnt;
RefCounters() : strong_cnt(0), weak_cnt(0) {}
};
从实现的角度,析构函数RefCounters::~RefCounters
应该什么都不做,因为它的所有成员都有基本类型。这意味着如果这个类型的对象被析构函数的显式调用破坏了(但是它的内存是而不是解除分配),那么在对象死后,我们将能够正常地使用它的成员。
现在假设我们有一些从RefCounters
派生的类。假设RefCounters
仅在Derived
类的基类中存在一次。假设为类Derived
的对象显式调用析构函数,但其内存为而不是解除分配。之后可以访问会员strong_cnt
和weak_cnt
吗?
从实现的角度来看,应该没问题,至少在没有涉及虚拟继承的情况下。因为Derived*
可以静态转换为RefCounters*
(将编译时常量偏移量加到地址中),并且RefCounters
的存储器不应该被Derived
类的析构函数触及。
下面是一个代码示例:
struct RefCounted : public RefCounters {
virtual ~RefCounted() {}
};
struct Base : public RefCounted {
int val1;
virtual void print();
};
struct Derived : public Base {
std::string val2;
virtual void print();
};
Derived *pDer = new Derived();
pDer->~Derived(); //destroy object
pDer->strong_cnt++; //modify its member
std::cout << pDer->strong_cnt << pDer->weak_cnt << "\n";
被认为是不确定的行为,例如由代码C++标准?有没有实际的原因可能导致它失效?可以通过微小的更改或添加一些约束来使其合法化吗?
P.S.假设这样的代码示例允许创建intrusive_ptr + weak_ptr组合,这样如果至少有一个weak_ptr指向它,总是可以从对象指针获取weak_ptr。更多详情,请参阅this question。
在一个不相关的说明中,为什么'RefCounters'本身不处理它的计数器呢?意思是析构函数*会做些什么(即减少一个或两个计数器)? –
由于'RefCounters'具有一个微不足道的析构函数,因此每当** [basic.life]/1 **时其存储被重用或释放时,它的生存期结束。显式的析构函数调用是不可操作的,不应该影响任何东西; “RefCounters”的特定实例也不是大对象的子对象。 –
@IgorTandetnik:谢谢你的评论。我想它应该使合法的第一种情况(即没有派生类)。但我仍然不确定派生类的第二种情况。 – stgatilov