[英]What is the relationship between the end of object's lifetime and when it ceases to exist?
在下面的簡短示例中,就在從main
返回之前,指針f
指向或用於指向的對象可以說些什么?
#include <vector>
struct foo {
std::vector<int> m;
};
int main()
{
auto f = new foo;
f->~foo();
}
我相信不再有f
曾經指向的對象foo
。 我收到了很多評論,說這可能不正確,而是可能有一個對象foo
處於銷毀、死亡或其他無效狀態。
對於顯式銷毀但其存儲仍然有效的對象的存在,語言標准有什么說法?
換句話說,是否可以合理地說在f
處仍然存在一個超出其生命周期的對象? 有沒有一個對象不在它的生命周期中,沒有開始構造並且沒有被破壞?
編輯 :
很明顯,一個對象可以在它不在其生命周期內時存在。 在構造和銷毀過程中,有一個對象,它的生命周期尚未開始或已經結束。 來自https://timsong-cpp.github.io/cppwp/intro.object#1 :
[...] 一個對象在其構建期間 ([class.cdtor])、整個生命周期和銷毀期間 ([class.cdtor]) 占用一個存儲區域。 [...]
但是在f->~foo();
f
指向的對象(我們稱之為o
)沒有被構造,它不在它的生命周期中,也沒有被破壞。 我對本節的理解是o
不能再占用存儲空間,因為它不在任何列舉的情況下。 這似乎意味着不再有o
並且不再有指向o
的指針。 相反,如果您有一個指向o
的指針,那么該指針將指向o
不能占用的存儲空間。
編輯2:
如果不再有對象,那么foo
有什么樣的值? 似乎它可以擁有的唯一合理的可能值是指向對象的指針,這與該語句相矛盾。 看到這個問題。
在 C++ 中,對象本質上是永恆的。 語言中沒有任何東西可以使對象消失。 超出其生命周期的對象仍然是一個對象,它仍然占用存儲空間,並且標准具有您可以使用指向其生命周期之外的對象的指針/引用來執行的特定操作。
一個對象只有在不可能有一個有效的指針/引用時才真正消失。 當該對象占用的存儲結束其存儲持續時間時,就會發生這種情況。 超過其持續時間的指向存儲的指針是無效指針,即使地址本身稍后再次有效。
因此,通過調用析構函數而不是使用delete f
(這也會釋放存儲), f
仍然指向foo
類型的對象,但該對象已超出其生命周期。
我上述陳述的理由基本上歸結為標准沒有任何規定來支持非創造對象的概念。
該標准提供了關於對象何時出現在存儲區中的清晰、明確的說明。 [intro.object]/1概述了激發對象創建的確切機制。
該標准提供了關於對象生命周期何時開始和結束的清晰、明確的陳述。 [basic.life]在其完全概述了這些事情,但 [basic.life]/1 特別解釋了對象的生命周期何時開始和結束。
該標准沒有提供任何關於對象何時不再存在的聲明(明確或其他)。 該標准規定了對象的創建時間、生命周期的開始時間以及結束時間。 但它從來沒有說它們何時停止存在於一塊存儲中。
也有人討論過這種形式的陳述:
任何表示對象將位於或曾經位於的存儲位置地址的指針都可以使用,但只能以有限的方式使用。
加了重點。
過去時的使用表明該對象不再位於該存儲中。 但是物體什么時候停止定位在那里呢? 沒有明確說明究竟是什么導致了這種情況的發生。 沒有那個,過去時態在這里的使用就無所謂了。
如果您不能指出它何時停止存在的聲明,那么您最多只能說標准中有幾個地方的措辭可以清理。 它並沒有消除標准沒有說明對象何時停止存在的明確事實。
但它確實說明了何時不再可以訪問對象。
為了使對象不再存在,標准必須考慮在這些對象不再存在時指向這些對象的指針。 畢竟,如果一個指針指向一個對象,那么該對象一定仍然存在,對嗎?
[basic.compound]/3概述了指針可以具有的狀態。 指針可以處於以下四種狀態之一:
- 指向對象或函數的指針(該指針被稱為指向該對象或函數),或
- 超過對象末尾的指針 ([expr.add]),或
- 該類型的空指針值 ([conv.ptr]),或
- 無效的指針值。
不允許指向任何對象的指針。 允許“無效指針值”,但指針僅在它們指向的存儲的存儲持續時間結束時才變為無效:
當到達存儲區域的持續時間結束時,表示該存儲區域的任何部分的地址的所有指針的值變為無效的指針值。
請注意,此語句意味着指向此類對象的所有指針不再處於“指向對象的指針”狀態並進入“無效指針”狀態。 因此,此類存儲中的對象(在其生命周期內和生命周期外)不再可訪問。
這正是標准需要存在的聲明以支持不再存在的對象的概念。
但不存在這樣的聲明。
[basic.life] 確實有幾個語句解決了可以使用指向生命周期之外的對象的指針的有限方式。 但請注意它使用的具體措辭:
對於正在構建或銷毀的對象,請參閱 [class.cdtor]。 否則,這樣的指針指向分配的存儲([basic.stc.dynamic.deallocation]),並且使用指針就像指針是 void* 類型一樣,是明確定義的。
它從不說指針“指向”分配的存儲。 它永遠不會撤銷 [basic.compound]/3 關於指針種類的聲明。 指針仍然是指向對象的指針; 只是指針“指向分配的存儲”。 並且該指針可以用作void*
。
也就是說,沒有“指向已分配存儲的指針”這樣的東西。 有一個“指向生命周期之外的對象的指針,其指針值可用於引用已分配的存儲空間”。 但仍然是“指向對象的指針”。
對象必須存在才能有生命周期。 標准清楚地表明了這一點。 但是,該標准在任何時候都沒有將對象的存在與其生命周期聯系起來。
事實上,如果結束一個對象的生命周期意味着該對象不存在,那么對象模型就會簡單得多。 [basic.life] 的大部分內容都是關於制定在該對象的生命周期之外使用對象名稱或指向它的指針/引用的特定方式。 如果對象本身不存在,我們就不需要那種東西。
在關於此事的討論中提到的是:
我相信提到生命周期外的對象是為了解釋正在構造的對象和正在銷毀的對象。
如果這是真的,那么[basic.life]/8 用這個語句談論的是什么:
如果在一個對象的生命周期結束后,在該對象所占用的存儲空間被重用或釋放之前,在原對象所占用的存儲位置創建一個新對象,一個指向原對象的指針,一個指向該對象的引用引用原始對象,或原始對象的名稱
如果在對象的生命周期結束時指向原始對象的指針變成指向已分配內存的指針,那么為什么此語句談論指向原始對象的指針? 指針不能指向不存在的對象,因為它們不存在。
只有當這些對象在其生命周期之外繼續存在時,這段話才有意義。 不,這不僅僅是在構造函數/析構函數中; 本節中的示例非常清楚地說明了這一點:
struct C {
int i;
void f();
const C& operator=( const C& );
};
const C& C::operator=( const C& other) {
if ( this != &other ) {
this->~C(); // lifetime of *this ends
new (this) C(other); // new object of type C created
f(); // well-defined
}
return *this;
}
C c1;
C c2;
c1 = c2; // well-defined
c1.f(); // well-defined; c1 refers to a new object of type C
雖然operator=
確實調用了析構函數,但該析構函數在使用this
指針之前完成。 因此,在創建新對象時, [class.cdtor]的特殊規定不適用this
。 因此,新對象是在對舊對象的析構函數調用之外創建的。
所以很明顯,對象的“在其生命周期之外”規則意味着始終有效。 它不僅僅是對構造函數/析構函數的規定(如果是,它會明確指出)。 這意味着名稱/指針/引用必須在其生命周期之外仍然命名/指向/引用對象,直到創建新對象。
為了實現這一點,他們命名/指向/引用的對象必須仍然存在。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.