2015-11-07 90 views
3

說我有這個類叫做Dog。每隻狗都有不同的名字,但有相同的叫聲(從資源文件加載)。一個對象的共享資源

class Dog { 
public: 
    Dog(const string &name) : _name(name) { 
     _barkingVoice.load(); 
    } 
    ~Dog() { 
     _barkingVoice.free(); 
    } 

    string getName() const { return _name; } 
    void bark() { _barkingVoice.play(); } 

private: 
    string _name; 
    VoiceResource _barkingVoice; 
}; 

我想打電話給_barkingVoice.load()只有狗的實例是第一位的,只有_barkingVoice.free()如果有狗沒有更多的實例。

顯而易見的解決方案是將_barkingVoice設置爲靜態,並將Dog的引用計數器作爲數據成員。

我的問題是如果有一個更簡單的方法來做到這一點。也許是std實現或類似的東西。

回答

2

做一個可重用的類來封裝引用計數:

template<class ResourceType, class OwnerType> 
class RefCounted { 
public: 
    RefCounted()   { if (++_refCount == 1) _resource.load(); } 
    virtual ~RefCounted() { if (--_refCount == 0) _resource.free(); } 
    ResourceType& operator*() { return _resource; } 
    ResourceType* operator->() { return &_resource; } 
private: 
    static unsigned _refCount; 
    static ResourceType _resource; 
}; 

template<class T, class U> unsigned RefCounted<T, U>::_refCount = 0; 
template<class T, class U> T RefCounted<T, U>::_resource; 

class Dog { 
public: 
    Dog(const string &name) : _name(name) { } 

    string getName() const { return _name; } 
    void bark() { _barkingVoice->play(); } 

private: 
    string _name; 
    RefCounted<VoiceResource, Dog> _barkingVoice; 
}; 

每個模板實例都會有自己的_refCount_resource

第二個模板參數用於處理您使用相同的ResourceType實例化RefCounted但希望爲這些實例分別引用計數的情況。例如。如果添加了Cat類,並希望它有它自己的Refcounted<VoiceResource>

class Cat { 
    // ... 
private: 
    RefCounted<VoiceResource, Cat> _meowingVoice; 
}; 
+0

太棒了。謝謝! – Pilpel

1

製作_barkingVoice a std::shared_ptr<VoiceResource>

A shared_ptr完全符合您的需求:使用引用計數來跟蹤最後一個對象的刪除時間,以便它釋放資源。

+1

這是好的,但如果我們創建'狗d(「」)',我們仍然需要找到已經創建的資源。 'shared_ptr'只會幫助複製/移動。 –

+0

是的。我猜這是行不通的。似乎我們必須手動實施參考計數,就像Lapshin Dmitry的回答一樣。 – emlai

2

首先,爲什麼VoiceResource不是靜態的?如果它在Dog的所有實例之間共享,則應該是。否則,您將需要在每個構造函數調用中加載或複製結果。

有一個靜態變量static int instanceCount;,即設置爲0。在每一個隨意,複製和移動(C++ 11)構造函數中增加它,在析構函數中遞減它。這會讓你有機會做你想做的事。

這將基本上像shared_ptr<T>一樣工作,可能是一種在這裏使用它的方式,而不是編寫自己的代碼,我只是無法弄清楚。

class Dog { 
public: 
    Dog(const string &name) : _name(name) { 
     loadResource(); 
    } 
    Dog(const Dog& b) : name(b.name) {    
     loadResource(); 
    } 
    // only C++11: 
    Dog(Dog&& b) : name(std::move(b.name)) { 
     loadResource(); 
    } 

    ~Dog() { 
     freeResource(); 
     _barkingVoice.free(); 
    } 

    string getName() const { return _name; } 
    void bark() { _barkingVoice.play(); } 

private: 
    string _name; 
    static VoiceResource _barkingVoice; 
    static int instanceCount; 

    static void loadResource() { 
     if (instanceCount == 0) { 
      _barkingVoice.load(); 
     } 
     ++instanceCount; 
    } 
    static void freeResource() { 
     --instanceCount; 
     if (instanceCount == 0) { 
      _barkingVoice.free(); 
     } 
    } 
}; 
int Dog::instanceCount = 0; 
+0

謝謝,但我的問題是如果有一個更短的方式做到這一點。我不想一次又一次地爲類似的類編寫所有的代碼。 – Pilpel

+0

@Pilpel考慮有一個資源管理器,它會將'shared_ptr <>'返回給請求的資源。這將會更清晰。 –