2014-10-04 87 views
2

我使用的框架,它有一個類註冊,我能註冊重載delete運算符來刪除庫

Register r; 
A * a1 = new A(); 
r->register(a1); 
A * a2 = new A(); 
r->register(a2); 

註冊將採取所有權A的情況下,在其中,並刪除所有已註冊分配的東西A當超出範圍。

我要修改共享庫(。所以在我的情況)A的行爲,所以,我會做這樣的事情(庫):

class B : public A { 
    ... 
} 

B * get_customized_a() { 
    return new B(); 
} 

然後在主程序

Register r; 
A * a1 = get_customized_a(); 
r->register(a1); 

但現在a1將在主程序中被刪除,而不是在圖書館!我認爲這是一個很大的禁忌。

那麼如何解決這個問題?


我提出了兩個解決方案:

1)使用和插件通過獨立的功能

定製:

void customize_a(A * a) { ... } 
主程序

Register r; 
A * a1 = new A(); 
customize_a(a1); 
r->register(a1); 

我一定要Ÿ我不喜歡那麼多:/

2)過載主程序刪除運營商B類的插件,

class B : public A { 
    ... 
    static void operator delete(void * ptr) { 
     ::operator delete(ptr); 
    } 
} 

Register r; 
A * a1 = get_customized_a(); 
r->register(a1); 

然而,我從來沒有過載operator delete之前,所以我不知道這是否會甚至工作(如預期)。

3)是否有我錯過任何方法?有更好的解決方案嗎?

謝謝大家。

+2

'A'是否有虛擬dtor?另外,你在哪個平臺上? – Deduplicator 2014-10-04 18:50:51

+0

不,如果我正確地閱讀源代碼,'A'沒有虛擬驅動器。平臺是Linux,AMD64 – Paladin 2014-10-04 18:56:39

+0

如果是Linux,你實際上不需要特別關心模塊邊界。儘管通過沒有虛擬dtor的基本類型刪除仍然保持UB。 – Deduplicator 2014-10-04 18:58:29

回答

0

如果通過使用一個指針到基類中的一個刪除類然後析構函數必須是在基類虛擬無論對象的創建和銷燬的位置。模塊邊界與此無關。

在如果一個對象的結構和銷燬不同模塊發生另一方面,它是隻有當這些模塊的新和刪除操作者從不同池分配/解除分配存儲器的問題。例如,如果這些模塊與運行時庫的不同版本鏈接,則可能是這種情況。類似的情況是,當您顯式重寫庫中的新操作符和刪除操作符時,您不需要在這些模塊的分配器代碼之間進行合作,而是從不同的池中進行分配。在這種情況下,虛擬析構函數並不能解決問題,因爲對象的構造使用一個模塊的分配器/池來分配內存,並且調用另一個模塊的delete操作符來嘗試從完全不同的對象中釋放對象池。結果通常是錯誤的「堆損壞」運行時錯誤或類似的東西。

如果您遇到過上述問題,那麼正確的解決方案是在基類中引入虛擬析構函數和虛擬Release()方法。 Release()方法應該刪除醜陋的對象delete this;。將構造的對象傳遞給外部模塊時,它必須通過調用Release()方法而不是直接刪除對象來刪除該對象,這樣Release()方法將刪除具有擁有該類和該實例的模塊的delete操作符的對象。通常這種技術與智能指針相結合,以便外部模塊通過調用Release()方法引用具有智能指針的這些對象,智能指針自動刪除對象。

+0

這並不能真正幫助我。我不能改變對象的保存方式(==不能切換到智能指針)或刪除(==不能通過'Release()'強制刪除),我不能控制該代碼。 – Paladin 2014-10-05 14:26:13

+0

@Paladin我寫了這個答案只是爲了澄清事情。你的問題有很多好的解決方案,我的文章沒有把路徑縮小到一個單一的黃金模式。如果你的基類包含一個虛擬的dtor,那麼你不必改變它的任何東西,因爲這兩個模塊都是從同一個堆中分配/釋放的。這個解決方案不與我的文章中的陳述相沖突。 – pasztorpisti 2014-10-05 16:40:12