5

如果我定義的operator delete如下,如果在新的表達式對象的構造函數拋出我期望看到在調用定義的運算符的結果刪除:當對象構造函數引入新表達式時,爲什麼不調用分配函數?

#include <new> 
#include <cstdlib> 
#include <iostream> 

void* 
operator new(std::size_t s){ 
    std::cout << "alloc " << std::endl; 
return std::malloc(s); 
} 

void 
operator delete(void* p) noexcept { 
    std::cout << "dealloc " << std::endl; 
    std::free(p); 
} 
void 
operator delete(void* p,std::size_t) noexcept{ 
    std::free(p); 
    std::cout << "dealloc s" << std::endl; 
} 

struct A{ 
    A(int i){ 
    if(i>0) 
     throw 10; 
    } 
}; 

int main(int argc// will equal 10 
     ,char* arg[]) 
{ 
    for(int i=0;i<argc;++i) 
    auto p=new A{argc}; 
    return 0; 
} 

這個程序只是輸出alloc,爲什麼運營商刪除不叫?在標準的[expr.new]它被指定的是:

如果上述對象初始化的任何部分通過拋出異常和合適 釋放函數可以發現終止,解除分配函數被調用,以自由其中正在構造對象 的內存,之後異常繼續在新表達式的上下文中傳播。

+0

您沒有try catch塊。 – Jarod42

+0

@ Jarod42你是對的!謝謝!我需要catch catch,因爲生活的主要功能是UB,還是出於其他原因? – Oliv

+0

這是UB部分。順便說一句,'return i;'是無效的('i'超出了範圍)。 – Jarod42

回答

1

如果你解決你的代碼拋出異常,它按預期工作:

int main(int argc,char* arg[]) 
{ 
    try { 
     new A(2); 
    } 
    catch (...) 
    {} 
} 

Demo

1

如果使用new建設過程中,一個構造函數拋出異常,C++運行時庫:

  1. 調用std::terminate()如果找不到合適的捕獲處理程序。 delete是否被調用是實現定義的。

  • 呼叫delete你之前如果發現,雖然析構函數不叫「發送」該異常到合適的catch處理 - 即~A(),如果你有一個,當i大於1時不會被調用。
  • +0

    我不認爲這適用於這裏:如果你捕獲異常,定義的刪除操作符IS被調用,而如果沒有捕獲,它不會被調用。所以你的「在給你這個例外之前」是非常含糊的。 – koalo

    +0

    @koalo是的,我已經做出了正確的答案。我修改了。 – Bathsheba

    2

    正如其他人已經提到的那樣,這是因爲你沒有發現異常。作爲標準的註釋:

    C++ 11§15.3/ 9
    「如果沒有發現匹配的處理器,函數std::terminate()被調用;在調用std::terminate()之前,堆棧是否展開是實現定義的。 」

    雖然我認爲這與你的情況沒有特別的關係,但同樣的原則也適用於此。因此,如果有任何內存被清除,它實際上取決於實現。正如我們在這裏看到的,通常情況並非如此,因爲操作系統無論如何都會清理內存。

    +0

    我對你的文章感興趣,因爲你回答「爲什麼?」。我不認爲這裏涉及內存清理。實現必須確保實際發生可見的副作用(內存清理可能不被視爲副作用)。 I/O是一種可見的副作用。所以Clang和GCC可能已經實現了內存釋放作爲堆棧展開過程的一部分,標準中沒有任何內容禁止這一點,並且在GCC文檔中,指定了終止不執行堆棧展開。謝謝,我明白了! – Oliv

    相關問題