2015-11-07 71 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 <>'返回给请求的资源。这将会更清晰。 –