2010-12-21 15 views
1

我忙於設計新的C++應用程序。在這個應用程序中,我想盡量減少指針的潛在錯誤,並且由於應用程序應該是普通的C++(沒有.Net或其他奇特的東西),我正在研究共享指針,我正在考慮在任何地方使用共享指針(而不是普通指針)。如何使用C++中的共享指針更容易地工作

我摸索出一些技巧,使其更容易與共享指針,例如工作:使用類中的一個typedef,就像這樣:

class X 
    { 
    public: 
     ... 
     typedef std::shared_ptr<X> Ptr; 
    }; 

這樣,你可以很容易地編寫X :: PTR,這比任何地方的「std :: shared_ptr」都更容易編寫。

我也注意到一些缺點共享指針:

  • 我到處都使用一個共享的指針我需要包括<memory>
  • 如果我只是想用指針,我不能再使用前置聲明

是否有任何其他技巧使共享指針更易於使用?

+2

我使用了一個類似於你之前建議的typedef,但是因爲我發現直接使用'shared_ptr '來更可讀。相反,我更喜歡將shared_ptr拉入全局名稱空間,以便更易於編寫(通過'using std :: shared_ptr;')。個人品味壽的事情。 – ltjax 2010-12-21 08:53:46

回答

7

不要!

使指針錯誤最小化的唯一方法是使用正確的指針類型。這就是類型,複數。

共享指針不是銀色子彈。他們成爲內存泄漏,一旦當你有循環引用(如果計劃將其在任何地方使用,這些將顯示很快)

如果你要無差錯的C++應用程序,你必須爲它工作。你必須瞭解你的應用程序。您必須瞭解不同對象的所有權語義。共享指針只是給你共享所有權,這通常是一個體面的最低分母。其他所有東西都可以被共享所有權所取代,它可以工作,有點。

但默認情況下是一個對象擁有一個其他實體。它由一個函數擁有,並且應該在該函數返回時被銷燬,或者它由一個類擁有,或者其他任何東西。通常,你根本不需要指針。對象可能按值存儲在std::vector中。或者它只是一個局部變量或類成員。如果一個指針,它會常常能更好地通過scoped_ptr或許一個允許所有權(unique_ptrauto_ptr)的傳輸表示。

shared_ptr是你可能會回落到時候你可以給任何一個對象的生命週期或所有權保證什麼。但是當你使用它時,你還需要使用weak_ptr來打破循環。

真的,更好的方法是儘量避免指針。當你需要一個指針,使用一個具有最具體的所有權語義的可能(喜歡scoped_ptr,不允許過戶的話,那麼如果你需要它,回落到一個允許您所有權,如unique_ptr,並且只作爲

萬不得已,你應該使用shared_ptr,它允許你自由地共享中的任何數量的客戶端的所有權。沒有什麼神奇的魔杖可以揮舞,使你的C++代碼「只是工作「實現這一目標的唯一方法是編寫出色的C++代碼,並且通過了解和使用這些工具,而不是假裝」嘿,shared_ptr就像垃圾收集器一樣,而不是它?我可以忽略所有問題如果我使用了對象生命週期或內存泄漏「。

+0

喊叫不要太過於戲劇化:-)小心,那些不是你想做的事情可能對人們的虛擬耳朵稍微有點仁慈。否則,我完全同意。 – 2010-12-21 10:43:04

+0

偶爾有點過度沒有問題。 ;) – jalf 2010-12-21 11:13:40

+0

實際上,由於它是如何工作的,shared_ptr可以在您將指針傳遞給本地對象的情況下提供服務。您可以將刪除器設置爲空操作,然後將其發送到該行。你當然會破壞關於shared_ptr的每一種語義,但是在捏的時候它就是一個竅門。 – 2010-12-21 17:17:00

1

關於typedef,你應該看看this question哪些解決完全相同的問題。

對於第二部分,我相信你是誤認爲std::shared_ptr可用於不完全類型,如N3225的20.9.10.2/2規定:

模板參數的shared_ptr T可能是不完整類型。

如果您當前的實施不支持,我認爲它應該被視爲一個錯誤。

+1

我可以不完整的聲明,但不是在使用。 shared_ptr 依賴於T的析構函數,與T * – BatchyX 2010-12-21 08:49:37

+0

@BatchyX不同:因此在使用析構函數時(就像使用delete時一樣),定義必須可用。沒有這麼大的變化。 – 2010-12-21 10:40:48

+0

並非shared_ptr的每個用法都會導致析構函數調用。例如,一個僅僅返回從容器中獲取的指針的函數不需要破壞任何東西,並且可以用不完整的類型來完成。用shared_ptr替換這個指針會強制定義類型,即使在這個函數中不能調用刪除。 – BatchyX 2010-12-21 11:09:57

3

不要只是選擇一個智能指針在任何地方使用。不是每個螺絲都是菲利普斯頭。

此外,您還可以使用前置聲明任何智能指針完全一樣的原始指針:

struct X; 

... 
std::shared_ptr<X> ptr; // legal 

struct X {}; 
ptr = std::shared_ptr<X>(new X); // legal 

這是我所聽到的SO這個誤解是第二次,它只是100%的假。

1

這是很常見的代碼有一個「慣例」,你然後按照,只要它是在你的團隊等一貫做的人就能理解它。

在「forward」文件中聲明共享指針typedefs要好得多。事情是這樣的:

namespace boost { template< typename T > class shared_ptr; } 

namespace MyStuff 
{ 
    class Foo; 
    class Bar; 
    class Baz; 

    typedef boost::shared_ptr<Foo> FooPtr; 
    typedef boost::shared_ptr<Bar> BarPtr; 
    typedef boost::shared_ptr<Baz> BazPtr; 

} 

有時你會想使用其他指針比shared_ptr的,但你的會議,然後將使用與XPTR意味着shared_ptr的不同符號。

當然你可以使用不同的表示法。

我認爲我們使用FooWeakPtr意味着weak_ptr<Foo> FooConstPtr意味着shared_ptr<const Foo>

例如。

應該在您的編碼標準文件中。

0

我喜歡這種做法吧:

namespace Internal 
    { 
     template <class T> 
     struct DeclareShared 
     { 
     typedef std::shared_ptr<T> type; 
     }; 

     template <class T> 
     struct DeclareUnique 
     { 
     typedef std::unique_ptr<T> type; 
     }; 
    } 

    // Inherit one of these classes to use a generic smart pointer interface. 

    // If class is abstract, use this interface. 
    template <class T> 
    struct SharedAbstract 
    { 
     typedef typename Internal::DeclareShared<T>::type APtr; 
    }; 

    template <class T> 
    struct Shared 
    { 
     typedef typename Internal::DeclareShared<T>::type Ptr; 

     template <class... P> 
     static Ptr shared(P&&... args) 
     { 
     return std::make_shared<T>(std::forward<P>(args)...); 
     } 
    }; 

    template <class T> 
    struct UniqueAbstract 
    { 
     typedef typename Internal::DeclareUnique<T>::type AUPtr; 
    }; 

    template <class T> 
    struct Unique 
    { 
     typedef typename Internal::DeclareUnique<T>::type UPtr; 

     template <class... P> 
     static UPtr shared(P&&... args) 
     { 
     return std::unique_ptr<T>(new T(std::forward<P>(args)...)); 
     } 
    }; 

增加了作用域PTR等,並不管你願意,你可以做這樣的事情更多的接口:

struct Foo : public Shared<Foo>, public Unique<Foo> 
{}; 

Foo::Ptr foo = Foo::shared(); 
Foo::UPtr unique = Foo::unique(); 

我不確定VS10如何處理可變模板,但至少在GCC4.5 +上工作良好。