如果我定義自己的new和delete運算子,如下所示:
#include <cstdio>
#include <cstdlib>
#include <new>
void* operator new (size_t count)
{
printf("Calling custom new!\n");
return malloc(count);
}
void operator delete(void *p) noexcept
{ printf("Called size unaware delete!\n");
free(p);
}
int main()
{
int *a = new int{1};
delete a;
}
gcc并使用版本 12.1編譯,并-O2 -Wall指定選項,我收到mismatched-new-delete警告。查看編譯后的輸出,我看到編譯器使用大小感知洗掉運算子(簽名void operator delete(void *p, std::size_t sz);)而不是我定義的自定義運算子(有關詳細資訊,請參閱編譯器資源管理器輸出)。
其他編譯器,例如clang使用我定義的洗掉運算子,因此不會導致不匹配的運算子警告。為什么gcc在優化時使用 size-aware 版本?
uj5u.com熱心網友回復:
參考后 C 20 草案 (n4861)。我還假設 C 14 或更高版本,它引入了大小感知釋放函式。
對于您的特定示例,呼叫 size-aware 需要洗掉運算式operator delete,因為要銷毀的型別是完整的。所以 GCC 的行為是正確的。(見[expr.delete]/10.5)
然而,選擇 size-aware 不是問題,因為全域operator delete(void*, size_t)多載的默認行為,如果不替換,只是呼叫相應的operator delete(void*),因此最終仍將使用您的自定義實作。(見[new.delete.single]/16)
然而,在[new.delete.single]/11中有一個建議,即替換operator delete不帶size_t引數版本的程式也應該替換帶引數的版本size_t。一個注釋澄清說,盡管目前標準庫提供了大小感知版本的默認行為,但無論如何都會呼叫自定義的非大小感知實作,但這可能會在未來的標準修訂版中發生變化。
此外,允許編譯器省略對給定示例的呼叫,以便operator new以operator delete不同的方式提供存盤,或者更有可能只是省略main沒有其他可觀察到的副作用的整個主體。所以有可能根本沒有operator delete呼叫 no 。
因此,為了使代碼適應未來并避免 linter 警告,還添加了一個替換大小感知全域多載的方法
void operator delete(void *p, std::size_t) noexcept
{
::operator delete(p);
}
另請注意,該標準要求替換此多載以使其始終可以通過呼叫不知道大小的版本來替換,而不會影響記憶體分配。(見[new.delete.single]/15)
雖然自 C 14 起就需要,但默認情況下,Clang 似乎還沒有啟用大小感知釋放功能。您需要添加-fsized-deallocation標志以啟用它們。
一些關于默認啟用它的補丁的討論似乎在這里進行。
另請注意,您的實作operator new已損壞。的拋出版本operator new不允許回傳空指標。所以你必須檢查它的回傳值,如果它為空則拋出malloc。std::bad_alloc
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/477240.html
