在析構函數中使用delete p,p前後指向的地址相同,而普通函數中用delete p,p前後指向的地址不同,代碼如下,望大佬賜教

#include &
using namespace std;

class Person {
public:

Person(int age, int height)
{
m_age = age;
m_height = new int(height);
}

~Person()
{
cout&

運行結果如下:


沒有意義,不要去費心費力研究它。


我對先前的惡意揣測深表歉意。經過更多的測試發現,似乎只有VS存在這個行為。並且這個行為並不屬於operator delete,而是直接插入delete語句處的,推測是VS為了方便及早發現涉及已釋放內存的bug而賦了一個無效值。

這個行為的觸發條件比較嚴格,傳右值(delete (int*)p;) 、有副作用的操作(delete (p=p);)、重新賦值會導致副作用(int* volatile p;)、成員變數(delete m_height;)都會阻止指針被修改。但將指針聲明為const並不能阻止,看起來編譯器比較任性()

關於成員變數為什麼不會被修改,我傾向於認為是為了保持對象的完整性,避免破壞設計時的某些約束;也可能是因為成員變數的定址方式比普通變數相對複雜,不值得為預防bug而付出運行時代價。


原回答:我懷疑你是偷偷改了程序後截的圖。00008123這甚至都不是個int*的合理取值。

delete不會改指針變數,而且語法上它沒有要求操作數是個變數,自然也沒辦法改什麼。


這是VS的鍋

簡單而言,在使用VS編譯時,其會默認開啟一個編譯選項/sdl,根據MSDN的介紹

https://docs.microsoft.com/en-us/cpp/build/reference/sdl-enable-additional-security-checks?view=msvc-160?

docs.microsoft.com

在開啟這個選項後,VC++會生成在運行期執行如下這個檢查的代碼

Does limited pointer sanitization. In expressions that dont involve dereferences and in types that have no user-defined destructor, pointer references are set to a non-valid address after a call todelete. This sanitization helps to prevent the reuse of stale pointer references.

如上所述,在test02函數中delete p; 後指針會被設置為一個無效的地址;而在test01中因為是在顯式定義的析構函數中執行delete ,所以指針不會被設置為一個無效地址,也即和delete 前指向相同的地址


首先,不管你用啥編譯器,delete p; 之後馬上p=null_ptr; 是一個好習慣。

其次,C++標準要求指針p被delete之後其所指地址無效,但是C++標準並沒有規定這時候p的值應該是多少。

VC相當於偷偷替你做了p=null_ptr這件事情,但這是非標準行為,最好不要依賴VC的這個特性。


這個問題問得不清楚,P是誰定義的,類型是類還是簡單類型。若是簡單類型沒什麼不同。


delete指針後立馬賦值nullptr,並不「總」是一個好習慣。他可能會掩蓋一些錯誤並使你的程序看似良好的繼續運行。因為delete nullptr在c++標準中有明確的定義。C++盡量總在析構里delete,用raii管理資源。如果你偶然想嘗試delete後置空,八成是因為你無法確定指針接下來有可能會在何處繼續使用,這樣的業務邏輯通常是有問題的或者你的理解有問題,在這時候你需要做的事就不僅僅是置空為null了。再退一步,如果你非要靠一個指針是不是nullptr來作為flag而沒有別的可靠的方案,還不如掏出shared_ptr.


推薦閱讀:
相关文章