2010-01-17 183 views
37

我有幾個容器中的一類,對於包含 shared_ptr的對居住在堆中的對象實例,載體或地圖。C++智能指針const正確性

例如

template <typename T> 
class MyExample 
{ 
public: 

private: 
vector<tr1::shared_ptr<T> > vec; 
map<tr1::shared_ptr<T> , int> h; 
}; 

我想有這個類,有時會返回shared_ptrs 爲const對象(通過shared_ptr<const T>)的公共接口,有時shared_ptr<T>其中 我允許呼叫者突變的對象。我想要邏輯常量的正確性,所以如果我將 方法標記爲const,它不能更改堆上的對象。

問題:

1)我由tr1::shared_ptr<const T>tr1::shared_ptr<T>互換性混淆。 當有人經過一個shared_ptr<const T> shared_ptr的進級,做我把它存爲載體內shared_ptr<T>shared_ptr<const T>和地圖或修改我的地圖,矢量類型(例如insert_elemeent(shared_ptr<const T> OBJ)?

2)它是更好地實例化類如下:MyExample<const int>?這似乎 不適當的限制,因爲我永遠不會返回shared_ptr<int>

回答

3

有一點要明白的是,:

tr1::shared_ptr<const T>被模仿的T const *即它所指向的是常量的功能,但指針本身是沒有的。

所以你可以給你的共享指針分配一個新的值,但我希望你不能使用取消引用的shared_ptr作爲l值。

+1

「l值」。一個l值不需要賦值! – curiousguy 2011-12-15 06:36:30

5

如果有人通過你一個shared_ptr<const T>你永遠不應該能夠修改T。當然,在技術上可以將const T轉換爲T,但這打破了製作Tconst的意圖。所以如果你希望人們能夠添加對象到你的班級,他們應該給你shared_ptr<T>shared_ptr<const T>。當你從班上回來的東西你不想修改,那就是當你使用shared_ptr<const T>

shared_ptr<T>可以自動轉換(沒有明確的轉換)爲shared_ptr<const T>,但不能反過來。它可以幫助你(無論如何你都應該這樣做)自由使用const方法。當您定義類方法const時,編譯器將不允許您修改任何數據成員或返回除const T之外的任何內容。因此,使用這些方法將幫助您確保您沒有忘記某些內容,並且可以幫助您的班級的用戶瞭解該方法的意圖。 (例如:virtual shared_ptr<const T> myGetSharedPtr(int index) const;

你在你的第二個說法是正確的,你可能不希望實例化類爲<const T>,因爲你將永遠不能修改任何你T S的。

34

shared_ptr<T> and shared_ptr<const T> are not interchangable。它有一種方法 - shared_ptr<T>可轉換爲shared_ptr<const T>但不是相反。

觀察:

// f.cpp 

#include <memory> 

int main() 
{ 
    using namespace std; 

    shared_ptr<int> pint(new int(4)); // normal shared_ptr 
    shared_ptr<const int> pcint = pint; // shared_ptr<const T> from shared_ptr<T> 
    shared_ptr<int> pint2 = pcint; // error! comment out to compile 
} 

編譯通過

CL/EHSC f.cpp

您也可以根據常量性重載函數。你可以結合做這兩個事實來做你想做的事情。

至於你的第二個問題,MyExample<int>可能比MyExample<const int>更有意義。

11

我建議以下methotology:

template <typename T> 
class MyExample 
{ 
    private: 
    vector<shared_ptr<T> > data; 

    public: 
    shared_ptr<const T> get(int idx) const 
    { 
     return data[idx]; 
    } 
    shared_ptr<T> get(int idx) 
    { 
     return data[idx]; 
    } 
    void add(shared_ptr<T> value) 
    { 
     data.push_back(value); 
    } 
}; 

這保證常量,正確性。就像你看到的add()方法不使用< const T>但是< T>因爲你打算這個類存儲Ts而不是const Ts。但是,當訪問它時,你會返回< const T>這是沒有問題的,因爲shared_ptr < T>可以很容易地轉換爲shared_ptr < const T>。並且sice中的get()方法都會將shared_ptr的副本返回到內部存儲中,調用者不會意外更改內部指針指向的對象。這完全可以與非智能指針變體相媲美:

template <typename T> 
class MyExamplePtr 
{ 
    private: 
    vector<T *> data; 

    public: 
    const T *get(int idx) const 
    { 
     return data[idx]; 
    } 
    T *get(int idx) 
    { 
     return data[idx]; 
    } 
    void add(T *value) 
    { 
     data.push_back(value); 
    } 
}; 
+0

難道不應該''shared_ptr '可以很容易地被轉換成 到shared_ptr '而不是其他方式嗎? – user231536 2010-01-17 16:13:02

+0

當只返回一個簡單的成員時,那麼超載似乎不是什麼大不了的事情。但是如果你從'vector'返回'shared_ptr' - 你必須計算哪一個是正確的。你如何避免代碼重複? – thomthom 2013-12-05 23:03:19