2011-10-18 28 views
2

一個任何保證,而以前,我們有這個聲明(簡體):我們可以依靠基於內存佈局和默認析構函數

宣言1

struct SomeType 
{ 
    // allocates Implementation in SomeType's TU 
    SomeType(); 
    // ... other stuff 
    struct Implementation 
    { 
    std::string someAtribute1; 
    std::string someAtribute2; 
    } 
    std::auto_ptr< Implementation> pimpl; 
}; 

一段時間以後,我們改變了去聲明這個(簡化):

宣言2

class OtherNameImplementation; 

struct SomeType 
{ 
    // allocates OtherNameImplementation in SomeType's TU 
    SomeType(); 
    // ... other stuff 
    std::auto_ptr< OtherNameImplementation> pimpl; 
}; 

OtherNameImplementationSomeType的TU中定義,並且與SomeType::Implementation(在聲明1中)具有完全相同的定義。

不知何故我們錯過了SomeType沒有定義的析構函數,因此編譯器生成的析構函數是在用戶的TU中定義的。

問題:

對於TU的已編譯反對「宣言1」是否有任何形式的擔保,該行爲是「正確」的時候,在運行時,它使用「宣言2」。

有,我能想到的兩個原因,它至少似乎「工作」:

  1. 編譯器生成的析構函數應該做「正確的事」,因爲內存佈局是相同的兩種實現類型,即使類型的名稱已更改。

  2. 我們有沒有注意到,在我們的測試期間任何影響(有數百個有這種依賴的應用程序)

我們的目標平臺是Solaris和我們使用Sunstudio 12

不知何故,我們在代碼審查過程中遺漏了這一點,我知道這至少是UB,並且在完美的世界中,我們將爲SomeType定義一個析構函數並重新編譯每個依賴於此的TU。

更新:

我「交叉張貼」這對comp.lang.C++哪裏阿爾夫P.施泰因巴赫讓我意識到,TU反對「宣言2」編譯正在泄漏內存(這是相當尷尬)。基於此,我們將恢復爲'聲明1'並重新編譯針對'聲明2'編譯的每個域,因此我們沒有標題或ABI解耦:)但我們處於有效狀態。我們將在下一個發佈週期中解決這個問題。

+0

除了Q,這是很好問,你不能重新編譯所有的代碼對新的修改重構代碼?恕我直言,對一塊代碼進行編譯並與另一塊代碼鏈接是一個非常糟糕的主意。 –

+0

如果您定義了TU和UB,它可能會有所幫助。 – gregg

+4

@gregg:這兩個術語(或至少兩個首字母縮略詞,翻譯單元和未定義行爲的擴展)都是由C++標準定義的。 –

回答

0

如果沒有基類/派生類並且沒有虛函數,那麼您引用的覆蓋保證是很好的。

我不認爲你被允許假設std :: auto_ptr或std :: string符合。

+0

我不明白爲什麼std :: auto_ptr或std :: string不能滿足這些要求。至少在我們的實現(RogueWave)中。 – Fredrik

+0

...此外,std :: auto_ptr(可能內聯)的析構函數只是調用「pimpl-type」(在用戶的TU中定義)的析構函數,該函數沒有virtual/base/sub。 - >爲每個屬性調用析構函數(這與內存完全相同)恕我直言std :: string的析構函數應該被正確調用,如果我們有保證的話。還是我誤解你? – Fredrik

+0

編譯器將內聯析構函數調用(它必須...)。我想如果你只用一個編譯器進行編譯並且從不發佈源代碼,那麼你可以假定該編譯器而不是每個允許存在的編譯器。 – Joshua

相關問題