2016-01-20 83 views
9

as-if rule」給予編譯器優化或重新排序表達式的權利,這些表達式在某些規則下不會影響程序的輸出和正確性,例如:as-if規則和刪除分配

§1.9.5

一致性實現執行合式程序應 產生相同的可觀察行爲的抽象機的相應實例的具有相同 程序可能執行 之一和相同的輸入。

的cppreference URL我上面鏈接特別提到了揮發性對象的值的特殊規則,以及爲「新的表現形式」,在C++ 14:

新表達有另外的異常從as-if規則:編譯器 可能會刪除對可替換分配函數的調用,即使提供了用戶定義的替換並且具有可觀察的副作用。

我承擔「替換」這裏是被談論例如在

§18.6.1.1.2

更換:C++程序可以定義使用此功能 簽名功能取代了由C++ 標準庫定義的默認版本。

它是正確的,下面mem可以在AS-如果統治下被刪除或重新排序?

{ 
    ... some conformant code // upper block of code 

    auto mem = std::make_unique<std::array<double, 5000000>>(); 

    ... more conformant code, not using mem // lower block of code 
    } 

有沒有一種方法可以確保它不會被移除,並停留在代碼的上下兩部分之間?一個放置良好的易失性(無論是/或揮發性標準偏差::陣列或左邊的自動)浮現在腦海,但由於沒有讀數mem,我認爲即使這不會幫助在作爲,如果規則。

附註;我一直無法讓visual studio 2015優化mem和分配。

說明:觀察的方式這將是對OS的分配調用來自兩個塊之間的任何I/O。這一點是針對測試用例和/或試圖在新位置分配對象的。

+1

我相信volatile會幫助那裏,但還有一個問題:沒有任何東西取決於mem值,所以編譯器可以在代碼塊的任何地方移動分配。它可能會在開始時,結束時和其他地方進行分配。 –

+0

@Revolver_Ocelot我不認爲揮發性甚至會有所作爲。 'make_unique'創建一個新對象,就我所知,由於潛在的副作用,C++編譯器不會優化對象的創建。他們可能會退出不必要的構造函數調用,但他們總是確保至少調用一個。否則,使用具有帶副作用的構造函數的RAII對象的代碼無法安全地依賴該模式,而不包含內存障礙。 – JAB

+0

** [intro.execution]/8 **表示「根據抽象機器的規則嚴格評估對易失性對象的訪問」。我把它看作「as-if規則不能應用於volatile對象」,所以它應該有所幫助。 –

回答

4

是;不在C++中。

C++的抽象機器根本不談論系統分配調用。只有影響抽象機器行爲的這種調用的副作用才由C++來解決,即使如此,編譯器也可以自由地做其他事情,只要 - 如果它導致了對於抽象機器部分的相同的可觀察行爲程序在抽象機器中。

在抽象機器中,auto mem = std::make_unique<std::array<double, 5000000>>();創建變量mem。它,如果使用的話,可以讓你訪問大量的數組打包到一個數組中。抽象機器可以自由地拋出異常,或向您提供大量的double;要麼沒事。

注意,它是一個合法的C++編譯器通過new與分配失敗(或返回nullptr對於沒有拋版本)無條件throw全部更換分配,但是這將是執行的質量差。

在分配它的情況下,C++標準並沒有真正說明它來自哪裏。例如,編譯器可以自由使用靜態數組,並使delete調用一個no-op(注意它可能必須證明它可以捕獲緩衝區上調用delete的所有方法)。接下來,如果你有一個靜態數組,那麼如果沒有人讀或寫它(並且構造不能被觀察到),編譯器可以自由地將其消除。


這就是說,上面的大部分依賴於編譯器知道正在發生什麼。

所以一種方法是讓編譯器不可能知道。讓你的代碼加載一個DLL,然後將一個指針指向unique_ptr指向那個你想要知道狀態的DLL。

由於編譯器無法優化運行時DLL調用,因此變量的狀態基本上應該是您所期望的。

不幸的是,沒有標準的方式來動態加載類似於C++的代碼,所以你必須依賴你當前的系統。

說的DLL可以分開寫成一個noop;或者,甚至可以檢查某個外部狀態,並根據外部狀態有條件地加載數據並將其傳遞給DLL。只要編譯器不能證明所述外部狀態將發生,它就不能優化圍繞所調用的而不是。然後,永遠不要設置該外部狀態。

聲明該塊頂部的變量。在未初始化時將指向它的指針傳遞給假外部DLL。在初始化之前重複,然後重複。最後,在摧毀它之前在塊的末尾執行它,.reset()它,然後再做一次。

+0

以下幾個問題中的哪一個是「否」回答? –

+2

@BenVoigt我看到兩個'?'。我現在已經回答了他們。 – Yakk

+1

你提到'throw'的時候很有趣,因爲這個異常在代碼塊之外是可以觀察到的,並且不能在高級代碼的副作用之前或者在低級的副作用之後出現。 –