假設我們有一個簡單的結構:派生類的破壞後基類的使用成員
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