2011-10-30 23 views
0

將對象作爲參數傳遞的好方法是什麼?在我的代碼中,我一直使用引用而不是指針,如果可能的話,我想堅持這種方法。但是,有一種情況下這不能正常工作:傳遞資源鎖定對象作爲參數

class Resource { 
    Resource(...) { //expensive resource initialization } 
    ~Resource() { //destroy resource } 
}; 

class User { 
    User(const Resource & res) : res_(res) { //initialize user } 
private: 
    Resource res_; 
} 

void Init() { 
    Resource res(...); 
    User user = new User(res); 
} //res is destroyed - along with its associated resource 
//user can no longer use the resource 

在這種情況下應該使用哪些最佳實踐?我想達到的結果是當User對象被銷燬時自動銷燬Resource,但不依賴於User對象創建Resource本身。我的感覺是我應該重載Resource的拷貝構造函數。任何其他想法?

+0

是否要在'User'對象之間共享'Resource'對象,或者只是在'User'對象外創建'Resource'對象? – msandiford

+0

我需要在'User'對象之間共享它們。 –

+4

不知道更多關於設計,我猜你想要''shared_ptr',它可以在boost,tr1或C++ 11標準中使用,具體取決於工具鏈的年齡。 http://www.boost.org/doc/libs/1_47_0/libs/smart_ptr/shared_ptr.htm – msandiford

回答

1

你最好的辦法是在User類中持有shared_ptr<Resource>成員。但是這需要在自由(堆)內存上生成資源。

class User { 
    User(Resource * res) : res_ptr(res) { //initialize user } 
private: 
    shared_ptr<Resource> res_ptr; 
} 

void Init() { 
    Resource * res = new Resource(...); 
    User user = new User(res); 
} 

第二種方法是爲Resource提供假複製構造函數和交換機制。

class Resource 
{ 
private: 
    explicit Resource(const Resource &); // disabled to avoid heavy copy. 
    const Resource & operator = (const Resource &); 
    int * int_res; 
public: 
    Resource() : int_res(new int(100)) { } 

    ~Resource() 
    { 
    if(int_res != NULL) 
     delete int_res; 
    } 

    Resource(Resource & other) : int_res(NULL) 
    { 
    this->swap(other); 
    } 

    void swap(Resource & other) 
    { 
    using std::swap; 
    swap(int_res, other.int_res); 
    } 
}; 

class User 
{ 
private: 
    Resource resource; 
    User(); 
    User(const User &); 
    const User & operator = (const User &); 
public: 
    User(Resource & res) : resource(res) { } 
    ~User() { } 
}; 

但是這樣做很危險且容易出錯,因爲在創建用戶之後,會使資源處於殭屍狀態。對於這段代碼,指向int_res指針的所有訪問權限(指向NULL)都會導致訪問衝突錯誤。

我能解釋的最後一種方法是使用C++ 0x功能「move semantics」。

class Resource 
{ 
// ... 
// ... 
    // Replace with Resource(Resource & other) 
    Resource(Resource && other) : int_res(NULL) //Move constructor 
    { 
    this->swap(other); 
    } 

    const Resource & operator = (Resource && other) // Move assignment operator 
    { 
     this->swap(other); 
     return *this; 
    } 

    void swap(Resource & other) 
    { 
    using std::swap; 
    swap(int_res, other.int_res); 
    } 
}; 

class User 
{ 
private: 
    Resource resource; 
    User(); 
    User(const User &); 
    const User & operator = (const User &); 
public: 
    User(Resource && res) : resource(std::move(res)) { } 
    ~User() { } 
}; 

void Init() { 
    Resource res(...); 
    User user = new User(std::move(res)); 
} 

這種方法有些安全。您不必處理指針,如果您忘記編寫std::move,則會收到編譯器錯誤,指出「您無法將Resource實例綁定到Resource&&」或「Resource的複製指令被禁用」。

&&強調該對象是臨時的,並將蒸發。所以這種方法更適用於由函數生成並返回資源的場景。如果我是你,我會使構造函數爲私人並使用朋友函數生成它。

Resource GetResource(....) 
{ 
    Resource res(...); 
    return res; 
} 

void Init() 
{  
    User user = new User(GetResource(...)); 
} 

這段代碼與「移動語義」是完美的表現。如果你能夠編寫C++ 0x代碼,你必須學習它。 Thisthis是兩個很好的視頻。

+0

'用戶(資源* res):res_ptr(res)'不要混合和匹配 - 使用'shared_ptr <>'或原始指針,而不是兩者的組合。 – ildjarn

+0

@ildjarn:我正在'User'類內部用'Resource'指針構造'shared_ptr'。這有什麼缺點? –

+0

缺點是'Resource'接受了原始指針的所有權 - 這些語義並不明顯。但是,如果'Resource'採用'shared_ptr <>'而不是原始指針,它們將會是。 – ildjarn

相關問題