2009-01-15 70 views
1

在我看來,一個類應該提供一個明確定義的抽象,並且不應該在沒有類的知識的情況下修改私有成員。但是當我檢查「auto_ptr」(或任何其他智能指針)時,違反了此規則。請參見下面的代碼auto_ptr design

class Foo{ 
public: 
    Foo(){} 
}; 

int main(int argc, char* argv[]) 
{ 
    std::auto_ptr<Foo> fooPtr(new Foo); 
    delete fooPtr.operator ->(); 
    return 0; 
} 

操作過載( - >)給出下面的指針,它可以不使用「的auto_ptr」的知識進行修改。我不能認爲這是一個糟糕的設計,因爲智能指針是由C++極客設計的,但我想知道他們爲什麼允許這樣做。有沒有辦法寫出沒有這個問題的智能指針。

欣賞你的想法。

+1

我想不出許多有用的類沒有這樣的事情。它很方便,但不要愚蠢。 `delete []&vector [0];` – 2012-03-21 22:15:01

回答

2

不,完全禁止在C++中使用這種不好的用法。

作爲一般規則,任何庫代碼的用戶都不應該在任何包裝的指針上調用delete,除非特別記錄。在我看來,所有現代C++代碼的設計都應該使得這些類的用戶從來沒有完全負責手動釋放她獲得的資源(即使用RAII)。

另外請注意:std::auto_ptr<T>不是最好的選擇了。它在複製時的不良行爲可能導致嚴重的編碼錯誤。通常更好的主意是使用std::tr1::scoped_ptr<T>std::tr1::shared_ptr<T>或其Boost變體。

此外,在C++ 0x中,std::unique_ptr<T>將在功能上取代std::auto_ptr<T>作爲更安全的類。關於該主題的一些討論和用於unique_ptr仿真的最新C++ 03實現可以在here找到。

+0

謝謝。我只是爲了解釋而使用auto_ptr。我正在使用boost :: shared_ptr。 RAII看起來很有趣 – 2009-01-15 03:17:35

+0

不知道爲什麼這個答案是downvoted ... – 2009-01-15 13:12:07

4

爲了提供對基礎對象的快速,方便的「指針式」訪問,operator->不得不「泄漏」它的抽象。否則,智能指針將不得不手動包裝允許公開的所有成員。這些實例化智能指針需要很多「配置」工作,或者C++中不存在的元編程級別。此外,正如pyrsta指出的那樣,即使這個漏洞被封堵,仍然有許多其他(也許是非標準的)方式來顛覆C++的訪問控制機制。

+0

這很有道理。謝謝 – 2009-01-15 03:18:12

2

有什麼辦法可以寫出沒有這個問題的智能指針。

這並不容易,一般也不會(即不能爲每一個普通的Foo類做)。

我能想到的,做到這一點,是通過改變Foo類的聲明的唯一方法:使Foo析構函數私人(或定義的私人delete運營商作爲Foo類的成員),並且還在類別Foo的聲明中指定std::auto_ptr<Foo>friend

+0

是的,這是我認爲的唯一方法。但是Foo必須進行修改,並且所有將與auto_ptr一起使用的類。這將是矯枉過正。 – 2009-01-15 03:15:59

5

有兩個所需特性的智能指針應具有:

  1. 原始指針可以被檢索(例如傳遞到傳統的庫函數)
  2. 原始指針不能被檢索(防止雙刪除)

顯然,這些特性是矛盾的,不能在同一時間實現! Even Boost's shared_ptr<Foo> et al。有get(),所以他們有這個「問題」。在實踐中,第一個更重要,所以第二個必須去。

順便說一句,我不知道爲什麼你伸手稍微隱晦operator->()當普通老get()方法會導致同樣的問題:

std::auto_ptr<Foo> fooPtr(new Foo); 
delete fooPtr.get(); 
0

我不認爲這表明auto_ptr的有封裝問題。無論何時處理擁有的指針,人們都必須理解誰擁有什麼。在auto_ptr的情況下,它擁有它保存的指針[1];這是auto_ptr抽象的一部分。因此,以任何其他方式刪除該指針都違反了auto_ptr提供的協議。

我會同意錯誤地使用auto_ptr [2],這非常不理想,但在C++中,您永遠無法避免「誰擁有這個指針?」這個基本問題,因爲爲了更好或者更糟的是,C++不會爲你管理內存。

[1]從cplusplus.com引用:「auto_ptr的對象有服用分配給它們的指針所有權的獨特性」:http://www.cplusplus.com/reference/std/memory/auto_ptr/

[2]例如,你可能會誤認爲它值語義,並將其用作矢量模板參數:http://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=4&ved=0CEEQFjAD&url=http%3A%2F%2Fwww.gamedev.net%2Ftopic%2F502150-c-why-is-stdvectorstdauto_ptrmytype--bad%2F&ei=XU1qT5i9GcnRiAKCiu20BQ&usg=AFQjCNHigbgumbMG3MTmMPla2zo4LhaE1Q&sig2=WSyJF2eWrq2aB2qw8dF3Dw

0

我認爲這個問題解決了一個非問題。智能指針用於管理指針的所有權,如果這樣做會使指針不可訪問,則它們失敗。

也考慮這個。任何容器類型都可以爲你提供迭代器;如果it是這樣的迭代器,則&*it是指向容器中的項目的指針;如果你說delete &*it那麼你已經死了。但是展示其物品的地址並不是容器類型的缺陷。