の破壊は我々が簡単な構造体があるとした後、基本クラスのメンバを使用:すべてのメンバーがプリミティブ型を持っているので、実装の観点から派生クラス
struct RefCounters {
size_t strong_cnt;
size_t weak_cnt;
RefCounters() : strong_cnt(0), weak_cnt(0) {}
};
を、デストラクタRefCounters::~RefCounters
は、何もしないはずです。これは、このタイプのオブジェクトがデストラクタの明示的な呼び出しで破棄された場合(そのメモリがではなく、が解放されている場合)、オブジェクトが正常に終了した後でメンバーと正常に作業できることを意味します。
は、今、私たちはRefCounters
から派生し、いくつかのより多くのクラスを持っていると仮定します。 RefCounters
が、基底クラスDerived
クラスの間に正確に1回存在するとします。デストラクタがクラスDerived
のオブジェクトに対して明示的に呼び出されたが、そのメモリがでなく、が割り当て解除されているとします。その後、メンバーstrong_cnt
とweak_cnt
にアクセスできますか?実装の観点から
は、それが少なくとも関与なし仮想継承がない場合、[OK]をする必要があります。 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のコンボを作ることができます。そのため、少なくとも1つのweak_ptrがまだポインタを指している場合、常にweak_ptrをオブジェクトポインタから得ることができます。詳細はthis questionを参照してください。
関連のないメモでは、なぜ、 'RefCounters'はそのカウンタ自体を扱わないのですか?デストラクター*が何かを行う(つまり、一方または両方のカウンターを減らす)ことを意味しますか? –
'RefCounters'は些細なデストラクタを持っているので、** [basic.life]/1 **ごとにストレージが再利用されたり解放されたりすると、そのライフタイムは終了します。明示的なデストラクタ呼び出しはノーオペレーションであり、何にも影響しません。 'RefCounters 'の特定のインスタンスがより大きなオブジェクトのサブオブジェクトであるという事実も考慮する必要はありません。 –
@IgorTandetnik:ご意見ありがとうございます。私は最初のケース(すなわち、派生したクラスなし)で合法にするべきだと思います。しかし、派生クラスの2番目のケースについてはまだ分かりません。 – stgatilov