一个对象的共享资源
说我有这个类叫做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实现或类似的东西。
做一个可重用的类来封装引用计数:
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;
};
制作_barkingVoice
a std::shared_ptr<VoiceResource>
。
A shared_ptr
完全符合您的需求:使用引用计数来跟踪最后一个对象的删除时间,以便它释放资源。
这是好的,但如果我们创建'狗d(“”)',我们仍然需要找到已经创建的资源。 'shared_ptr'只会帮助复制/移动。 –
是的。我猜这是行不通的。似乎我们必须手动实施参考计数,就像Lapshin Dmitry的回答一样。 – emlai
首先,为什么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;
谢谢,但我的问题是如果有一个更短的方式做到这一点。我不想一次又一次地为类似的类编写所有的代码。 – Pilpel
@Pilpel考虑有一个资源管理器,它会将'shared_ptr '返回给请求的资源。这将会更清晰。 –
太棒了。谢谢! – Pilpel