一個任何保證,而以前,我們有這個聲明(簡體):我們可以依靠基於內存佈局和默認析構函數
宣言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;
};
凡OtherNameImplementation
在SomeType
的TU中定義,並且與SomeType::Implementation
(在聲明1中)具有完全相同的定義。
不知何故我們錯過了SomeType
沒有定義的析構函數,因此編譯器生成的析構函數是在用戶的TU中定義的。
問題:
對於TU的已編譯反對「宣言1」是否有任何形式的擔保,該行爲是「正確」的時候,在運行時,它使用「宣言2」。
有,我能想到的兩個原因,它至少似乎「工作」:
編譯器生成的析構函數應該做「正確的事」,因爲內存佈局是相同的兩種實現類型,即使類型的名稱已更改。
我們有沒有注意到,在我們的測試期間任何影響(有數百個有這種依賴的應用程序)
我們的目標平臺是Solaris和我們使用Sunstudio 12
不知何故,我們在代碼審查過程中遺漏了這一點,我知道這至少是UB,並且在完美的世界中,我們將爲SomeType
定義一個析構函數並重新編譯每個依賴於此的TU。
更新:
我「交叉張貼」這對comp.lang.C++哪裏阿爾夫P.施泰因巴赫讓我意識到,TU反對「宣言2」編譯正在泄漏內存(這是相當尷尬)。基於此,我們將恢復爲'聲明1'並重新編譯針對'聲明2'編譯的每個域,因此我們沒有標題或ABI解耦:)但我們處於有效狀態。我們將在下一個發佈週期中解決這個問題。
除了Q,這是很好問,你不能重新編譯所有的代碼對新的修改重構代碼?恕我直言,對一塊代碼進行編譯並與另一塊代碼鏈接是一個非常糟糕的主意。 –
如果您定義了TU和UB,它可能會有所幫助。 – gregg
@gregg:這兩個術語(或至少兩個首字母縮略詞,翻譯單元和未定義行爲的擴展)都是由C++標準定義的。 –